3
0
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:
Olivier Parcollet 2013-09-07 15:27:10 +02:00
parent 27be5cbd5b
commit 2c542647fd
41 changed files with 813 additions and 980 deletions

View File

@ -1,58 +1,70 @@
.. highlight:: c
Automatic assignment
=======================
Automatic assignment of containers
===================================
Principle
----------------
Another use of expression is the automatic assignment of containers.
It is possible to use a subset of possible expressions as Left Hand Side (LHS) in an assignment statement, e.g. ::
**Synopsis** :
A(x_) = some_expression_of_x_
A[i_] = some_expression_of_i_
A(x_)(i_,j_) = some_expression_of_x_i_j
A[x_](i_,j_) = some_expression_of_x_i_j
If C is a container, ::
* Right Hand Side (RHS) of the = statement can be any expression.
* Left Hand Side (LHS) of the = sign. A must be a `lazy-assignable`, called by [] or (), one or several time.
C(x_) << some_expression_of_x_
C[i_] << some_expression_of_i_
C(x_)(i_,j_) << some_expression_of_x_i_j
C[x_](i_,j_) << some_expression_of_x_i_j
This writing means that a regular function ::
x_ -> some_expression_of_x_
depending of course of the operator that the container support.
The Right Hand Side (RHS) of the << statement can be any expression,
while Left Hand Side (LHS) of the << sign is a container supporting the operation (see below).
will be given to A so that it can fill itself by evaluating this function.
A determines the range of value of x on which the function is called.
This statement simply will be rewritten by the CLEF library as ::
Example
---------
triqs_clef_auto_assign (C, x_ -> some_expression_of_x_); // pseudo code
triqs_clef_auto_assign (C, [](auto x_) {return some_expression_of_x_;}); // or in C++ lambda syntax
The function `triqs_clef_auto_assign` has to be overloaded for the container and the correct
functional form, and it is expected to fill C by evaluating this function.
Such a function is provided for TRIQS objects (arrays, matrix, Green function),
and also for some STL container like std::vector.
Example :
.. compileblock::
#include "triqs/clef.hpp"
#include "triqs/clef/adapters/vector.hpp"
#include <iostream>
using namespace triqs::clef;
int main() {
int N = 10;
int N = 5;
double pi = std::acos(-1);
std::vector<double> V(N);
// automatic assignment of vector and use of lazy math function
triqs::clef::placeholder <0> k_;
triqs::clef::lazy(V) [k_] << cos( (2* pi* k_)/ N );
// automatic assignment of vector
placeholder <0> k_;
std::vector<double> V(N);
make_expr(V) [k_] << cos( (2* pi* k_)/ N );
// chaining them ...
placeholder <1> i_;
std::vector<std::vector<double>> W(3, std::vector<double>(N));
make_expr(W)[i_] [k_] << i_ + cos( (2* pi* k_)/ N );
// check result...
for (size_t u=0; u<V.size(); ++u) std::cout<< u << " "<<V[u]<< " "<< cos((2*pi*u)/N)<<std::endl;
for (size_t u=0; u<V.size(); ++u) if (std::abs(V[u] -cos((2*pi*u)/N))> 1.e-10) throw "error!";
for (size_t w=0; w<W.size(); ++w)
for (size_t u=0; u<W[w].size(); ++u)
if (std::abs( W[w][u] - (w+cos((2*pi*u)/N)))> 1.e-10) throw "error!";
}
Implementing automatic assign for an object
------------------------------------------------------------
**Details**
It is sufficient to add a function ::
The synopsis of the `triqs_clef_auto_assign` functions is ::
template<typename Fnt> void triqs_clef_auto_assign (Obj & x, Fnt f);
The compiler will rewrite ::
The compiler will then rewrite ::
obj(x_,y_, ...) = expression
@ -60,7 +72,7 @@ into ::
triqs_clef_auto_assign (obj, make_function( expression, x_, y_, ....))
The function is found by ADL. It is therefore useful to implement it e.g. as a friend function.
The function must be found by ADL. It is therefore useful to implement it e.g. as a friend function.
Similarly, for [ ], adding a function ::
@ -82,33 +94,22 @@ A complete example :
#include <triqs/clef.hpp>
#include <iostream>
using namespace triqs::clef;
struct Obj{
double v;
Obj(double v_): v(v_){}
// lazy call : cf ...
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const Obj>,Args...>::type
operator()( Args&&... args ) const { return make_expr_call (std::ref(* this),args...);}
// The non const version (which then stores a non-const reference ....)
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<Obj>,Args...>::type
operator()( Args&&... args ) { return make_expr_call (std::ref(* this),args...);}
template<typename Fnt> friend void triqs_clef_auto_assign (Obj & x, Fnt f) {
x.v++; std::cout<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;
}
friend std::ostream & triqs_clef_formal_print(std::ostream & out, Obj const & x) {return out<<"Obj";}
double v;
TRIQS_CLEF_IMPLEMENT_LAZY_CALL();
//
template<typename Fnt> friend void triqs_clef_auto_assign (Obj & x, Fnt f) {
std::cout<< " called triqs_clef_auto_assign "<< f(x.v++)<<std::endl;
}
};
int main() {
Obj f(2);
triqs::clef::placeholder<3> x_;
std::cout<< f.v << std::endl;
f(x_ ) << 8*x_ ;
//f(x_ + y_) = 8*x_; // leads to a compile error as expected
std::cout<< f.v << std::endl;
Obj f{2};
placeholder<3> x_;
std::cout<< f.v << std::endl;
f(x_ ) << 8*x_ ;
std::cout<< f.v << std::endl;
}

View File

@ -1,25 +1,27 @@
Clef expressions library
Clef
*************************************
.. highlight:: c
.. warning::
This library is still a prototype, of alpha quality.
Documentation is not fully up to date : work in progress.
This library is still a prototype. Its basic features are used in our codes, but
there are probably still some dark corners ...
Documentation in progress.
The CLEF library (**C**\ompile time **L**\azy **E**\xpressions and **F**\unctions) is a little
library to manipulate simple expressions at compile-time and use them e.g.
to automatically fill containers.
The little CLEF library (Compile time Lazy Expression and Function)
is a simple lambda library for C++11, to store and code formal expressions
using placeholders.
.. toctree::
:maxdepth: 1
:maxdepth: 2
introduction
expressions_form
expressions_eval
function
lazy_call
assign
lazy_function_cls
overload
function
examples/contents

View File

@ -1,40 +0,0 @@
Copy policy in building expressions [Advanced]
====================================================
When building expressions, a problem can appear for the object at the leaves of the expressions tree
(scalar, placeholders, various callable objects, etc...).
The question is whether they should be captured by value or by reference.
In the lazy library, the choice has been made to capture them **by value**.
This means that, by default, *all objects appearing in a lazy expression are copied, rather than captured by reference*.
This is necessary to store expressions (with auto like above) for future reuse, transform them into new expressions
(e.g. make partial evaluation). Expressions are objects.
Capturing the leaves by reference easily produces dangling references.
[Basically, an expression is a function of its placeholder. The leaves are the parameters of the function,
they must leave as long as the expression live. In other words, we need to have a closure of the function].
The drawback of this approach is that it can generate unless copies of large objects.
There are several solutions to this issue :
* The object is very small (like a double), hence making a copy in not a problem.
* You *know* that the object `A` will survive the expression, so using a reference is not a problem.
You can use the `lazy(A)` expression that will wrap the reference to the object.
* The object has a compagnon view object (like array, array_view). In this case,
one wishes to put a view of the object rather than a copy in the expression.
There are two cases.
* TRIQS objects like array, matrix, vector will do it automatically.
* For another object, if the object defines the tag `has_view_type_tag` as ::
typedef void has_view_type_tag;
typedef MY_VIEW_TYPE view_type;
the instance of the object will be replaced by an instance of its view_type in building the expression.
For an illustration, Cf....

View File

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

View File

@ -1,16 +0,0 @@
.. highlight:: c
.. _lazy_function_ex:
Using clef::function
-----------------------------
The following code :
.. literalinclude:: src/lazyfunction.cpp
will print :
.. literalinclude:: src/lazyfunction2.output

View File

@ -3,18 +3,13 @@
A lazy sum
--------------
Problem : we want
* a functional `sum` that sums a function f over various domains, with various methods.
* that this functionnal accepts lazy expressions as arguments.
This is done by the little code:
Here is a little functional `sum` that sums a function f over various domains
and accepts lazy expressions as arguments.
.. literalinclude:: src/sum_functional.cpp
which will print :
Compiling and running this code reads :
.. literalinclude:: src/sum_functional2.output
.. literalinclude:: src/sum_functional.output

View File

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

View File

@ -1,25 +0,0 @@
.. highlight:: c
std::vector and math
---------------------------------
A simple example using std::vector.
.. compileblock::
#include "triqs/clef.hpp"
int main() {
// init some variables
int N = 10; double pi = std::acos(-1); std::vector<double> V(N);
// Filling the vector automatically from an expression of k_
triqs::clef::placeholder<0> k_;
triqs::clef::lazy(V) [k_] << cos( (2* pi* k_)/ N );
// check result...
for (size_t u=0; u<V.size(); ++u)
std::cout<< u << " "<<V[u]<< " "<< cos((2*pi*u)/N)<<std::endl;
}

View File

@ -1,113 +0,0 @@
.. highlight:: c
Forming lazy expressions
===========================
Expressions are composed from :
* Placeholders
* Binary operations on expressions `(+, -, *, /, >, <, >=, <=, ==)`
* Callable objects (see below) called on expressions
* Conditional if_else expressions
Placeholders
----------------
Placeholders are only defined by their type, they contain no data ::
triqs::lazy_expressions::placeholder <DOM,1> x_;
triqs::lazy_expressions::placeholder <DOM,2> y_;
.. warning::
As a consequence, if you define::
triqs::clef::placeholder <DOM,2> y_;
then `x_` is the same as `y_` : `x_` == `y_` will be always true.
Callable objects
--------------------
* The header `math.hpp` contains the declaration to make
the basic function of std `math.h` accept lazy_expressions.
Example ::
#include <triqs/clef/math.hpp>
cos(2*x_+1) (x_=2) ;
abs(2*x_-1) (x_=2) ;
floor(2*x_-1) (x_=2.3) ;
pow(2*x_+1,2) (x_=2) ;
* To make your object callable, or to overload a function to accept lazy argument, see :ref:`callable_object`.
Copy policy
--------------------
.. warning:: All objects appearing in a lazy expressions are copied, rather than captured by reference.
This is necessary to store expressions, make partial evaluation.
In order to avoid unncessary copies for large objects, it is necessary to use view type objects ( or shared_ptr).
**NB** : for array, matrix, vector of the triqs::arrays library, this is automatic : triqs::clef
takes a *view* of the objects when building the expression tree.
Evaluating lazy expressions
===============================
Complete evaluation
--------------------
Expressions are evaluated used named arguments, following the pattern ::
expression ( placeholder_1 = value_1, placeholder_2 = value_2, ...)
Example ::
(x_ + 2*y_) ( x_=1, y_ = 2)
// or (in C++11)
auto e = x_ + 2*y_;
auto r = e ( x_=1, y_ = 2);
Note that :
* The order of placeholder does not matter
* It is an error to put the same placeholder twice.
Partial evaluation
--------------------
The evaluation can also be partial, in which case the compiler replaces the placeholder whose value is provided
and rebuild a new expression tree.
Example ::
auto expr = x_ + 2*y_;
expr (x_ =1); // ---> 1 + (2 * y_)
expr (x_ =x_ + y_); // ---> ((x_ + y_) + (2 * y_))
expr(x_ =x_ + y_)( x_ = 1, y_ = 2)); //---> 7
During the partial evaluation, all subtrees that can evaluated are evaluated.
For example ::
(x_ + f(y_)) (y_=1); // --> x + f(1)
Assignment
------------
Some objects are `lazy-assignable`, which means that calling them on placeholders is a possible LHS.
Expressions like ::
F(x_,y_) = an_expression_of(x_,y_);
are rewritten by the compiler into ::
F.set_from( make_function( an_expression_of(x_,y_), x_, y_) );

View File

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

View File

@ -1,28 +1,25 @@
.. highlight:: c
Introduction
Forming CLEF expressions
===========================
The first step consists in forming lazy expressions, before evaluating them.
In this section, we describe how to form CLEF expressions.
Placeholders
----------------
-------------------
Loosely speaking, a placeholder is a "variable name" used to build an expression.
Technically, it is a trivial object, with a type but containing no data.
Placeholders are declared as ::
placeholder<Number> Name;
This declares a placeholder called Name (an empty object for C++).
Example ::
placeholder <1> x_;
placeholder <2> y_;
Note that the only thing of significance in a placeholder is its type, since it contains no data.
In other words, a placeholder is **empty**. It contains **no value** at runtime.
Note that the only thing of significance in a placeholder is its type (i.e. Number).
A placeholder is **empty** : it contains **no value** at runtime.
.. warning::
@ -33,18 +30,62 @@ In other words, a placeholder is **empty**. It contains **no value** at runtime.
would imply that `x_` is the same as `y_` : `x_` == `y_` will be always true.
Forming an expression
-------------------------
------------------------
Using simple operators, one can form a more complex expression, e.g.::
CLEF expressions are made of :
* Placeholders
* Binary operations on expressions `(+, -, *, /, >, <, >=, <=, ==)`
* Ternary conditional if_else expressions
* Callable objects which overload the operator () for CLEF expressions, See :ref:`callable_object`.
* Functions overloaded for CLEF expressions. For example, the header `math.hpp` contains the declaration to make
the basic function of std `math.h` accept CLEF_expressions.
* In fact, almost anything : the *make_expr* function can be called on any object to make it lazy.
Examples :
.. compileblock::
#include <triqs/clef.hpp>
#include <vector>
using namespace triqs::clef;
int main () {
placeholder<0> i_; placeholder<1> x_; placeholder<2> y_;
std::vector<int> V;
// arithmetic
auto e = x_ + 2* y_;
// simple math function
auto e1 = cos(2*x_+1);
auto e2 = abs(2*x_-1);
// making V lazy
auto e0 = make_expr(V)[i_];
}
Note that :
* Expressions do not compute anything, they just store the expression tree.
* There is no check of correctness here in general : an expression can be well formed,
but meaningless, e.g. ::
auto e = cos(2*x_, 8); // !
.. highlight:: c
Storage of expressions [advanced]
-----------------------------------
CLEF expressions have a complicated (expression template) type encoding the structure of the expression
at compile time::
auto e = x_ + 2* y_;
e has a complicated type (it is an expression template), which encodes the structure of the expression.
Typically here something like ::
// the type of e is something like
expr<tags::plus, placeholder<1>, expr<tags::multiplies, int, placeholder<2> >
It is worth noting that :
Note that :
* As a user, one *never* has to write such a type
One always use expression "on the fly", or use auto.
@ -52,81 +93,27 @@ It is worth noting that :
* Having the whole structure of the expression at compile time allows
efficient evaluation (it is the principle of expression template : add a ref here).
* Declaring an expression does not do any computation, hence the name of the library (lazy ...).
* Declaring an expression does not do any computation.
It just stores the expression tree (its structure in the type, and the leaves of the tree).
What is allowed in clef expressions ?
==========================================
* Every object in the expression tree is captured by :
Expressions are composed of :
* reference it is an lvalue.
* Placeholders
* Binary operations on expressions `(+, -, *, /, >, <, >=, <=, ==)`
* Conditional if_else expressions
* Callable objects (see below) called on expressions
Callable objects
--------------------
* Objects can overload the operator () for lazy expressions in order to build more complex
expressions.
* For example, the header `math.hpp` contains the declaration to make
the basic function of std `math.h` accept lazy_expressions.
.. compileblock::
* value it is an rvalue : an rvalue (i.e. a temporary) is *moved* into the tree, using
move semantics.
#include <triqs/clef.hpp>
int main () {
triqs::clef::placeholder <1> x_;
Exceptions : the following objects are always copied : placeholders, expression themselves.
auto e1 = cos(2*x_+1);
auto e2 = abs(2*x_-1);
auto e3 = floor(2*x_-1);
auto e4 = pow(2*x_+1,2);
}
Example ::
* To make your object callable, or to overload a function to accept lazy argument, see :ref:`callable_object`.
*lazy* function
-------------------
The *lazy* function can be called on any object to make it lazy, e.g.
.. compileblock::
#include <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.
double a = 3;
auto e = a + 2* x_ ; // a is stored by reference (double &), but 2 is stored by value
The rational is as follows :
* rvalue must be moved, otherwise we would keep (dangling) reference to temporaries.
* for lvalue, keeping a reference is quicker. Of course, in the previous example,
it is mandatory that a live longer than e ...

View File

@ -1,8 +1,8 @@
.. highlight:: c
Clef expressions vs functions
=====================================================================
Transform CLEF expressions into functions
===============================================
Clef expressions are **NOT** functions. In short,
@ -14,22 +14,12 @@ Clef expressions are **NOT** functions. In short,
f(1,2)
It is however possible to transform expressions into functions, *as soon as you specify the order of the placeholders*,
and back.
Function to clef expressions
-------------------------------------
This is immediate, if the function accept lazy arguments, cf :ref:`callable_object`::
auto e1 = f(x_);
It is however possible to transform expressions into functions, *as soon as you specify the order of the placeholders*.
(the opposite is true, if the function accept lazy arguments, cf :ref:`overload_function`).
Transforming clef expressions into functions
----------------------------------------------------
make_function
.....................
make_function
---------------
Given any expression with placeholder `x_`, `y_`, `z_`, ..., `make_function`
transform them into a regular function. If we say ::
@ -38,41 +28,13 @@ transform them into a regular function. If we say ::
then f is ::
a function (placeholder_1, placeholder_2, placeholder_3, ...) --> RESULT
a function (x1,x2,x3) --> RESULT
where RESULT is :
* the result of the complete evaluation of the expression if the list of placeholder exhausts the placeholders of the expression.
* otherwise a clef_expression of the remaining placeholders, returning a **function**.
Examples :
* With one variable::
auto e1 = 2*x_ + 1;
auto f = make_function( e1, x_);
f(3) == 7; // ok
std::function<double(double)> F(f); // ok
* With two variables ::
auto e2 = 2*x_ + y_ + 1;
auto f = make_function( e2, x_, y_);
f(3,4) == 11; // ok
std::function<double(double,double)> F(f); // ok
* Make a function partially ::
auto f = make_function( 2*x_ + y_ + 1, x_);
// f is a lazy expression expression with placeholder y_, returning a function...
auto f1 = eval (f, y_=1); // f1 is a function x-> 2*x + 2
f1 (10) == 22;
* Currifying a function ::
auto f = make_function ( make_function( 2*x\_ + y\_ + 1, x\_), y\_);
// f a function y-> x-> 2x+y+1
// f(y) returns a function x-> 2x+y+1
Short notation with >> operator
.....................................
@ -95,4 +57,67 @@ For function of *one* variable, the make_function notation can be simplified int
is banned because it conflicts with the standard priority of >>.
Use parenthesis.
clef::function
--------------------------
The class triqs::clef::function stored a function of a given signature
It is similar to std::function but
it can be constructed from an expression and an ordered list of placeholders.
clef::function can be assigned with the = operator, Cf example below.
.. note::
Like std::function, it stores the expression polymorphically, by erasing its type.
This might lead to some performance penalty in some case, even though tests do not show that at present...
Examples
---------
.. compileblock::
#include <triqs/clef.hpp>
#include <iostream>
using namespace triqs::clef;
int main() {
placeholder<0> x_; placeholder<1> y_;
{ // with one variable
auto f = make_function(2*x_ + 1, x_);
std::cout << f(3) << std::endl;
std::function<double(double)> F(f);
}
{ //with two variables
auto f = make_function(2*x_ + y_ + 1, x_, y_);
std::cout << f(3,4) << std::endl;
std::function<double(double,double)> F(f);
}
{ // Make a function partially
auto f = make_function( 2*x_ + y_ + 1, x_);
// f is a lazy expression expression with placeholder y_, returning a function...
auto f1 = eval (f, y_=1); // f1 is a function x-> 2*x + 2
std::cout << f1 (10) << std::endl;
}
{ // Currying a function
//auto f = make_function ( make_function( 2*x_ + y_ + 1, x_), y_);
auto f = y_ >> ( x_ >> 2*x_ + y_ + 1);
// f a function y-> x-> 2x+y+1
// f(y) returns a function x-> 2x+y+1
auto g = f(3);
std::cout << g (10) << std::endl;
}
{ // playing with clef::function and std::function
triqs::clef::function<double(double,double)> f2,g2;
f2(x_,y_) = x_ + y_;
std::cout << f2(2,3) << std::endl;
std::function<double(double,double)> sf2 = f2;
std::cout << sf2(2,3) << std::endl;
g2(x_,y_) = x_ - y_ + f2(x_,2*y_);
std::function<double(double)> sf = x_>> 2*x_ + 1;
std::cout << sf(3) << std::endl;
}
}

View File

@ -1,15 +1,72 @@
.. highlight:: c
Motivation
=======================
Motivation : a little tour of CLEF
=====================================
A usual, the best is to start with a few examples, to show the library in action.
The purpose of the Named Parameter Lambda (nplambda) library is to help
the manipulation of formal expressions.
.. compileblock::
#include <triqs/clef.hpp>
#include <triqs/arrays.hpp>
#include <iostream>
#include <algorithm>
int main() {
// Declaring some placeholders (i.e. dummy variables).
triqs::clef::placeholder <0> i_;
triqs::clef::placeholder <1> j_;
// Declaring a 3x3 matrix
triqs::arrays::matrix<double> A (3,3);
// Automatically filling the matrix
// -> forget about the bounds, it is automatic
// -> forget about the best order to order the for loops for performance, it is also automatic
A(i_,j_) << i_ + 2*j_;
// Cheking the result
std::cout<< A<< std::endl;
// It also works for std container: we just have to add a call clef::make_expr function
std::vector<double> V(10);
double pi = std::acos(-1);
// Automatically filling the vector with the evaluation of the expression in i_
triqs::clef::make_expr(V) [i_] << cos( 2* pi / 5.0 * i_ );
// -> by the way, the constant calculation is precomputed
// (expressions are partially evaluated as soon as possible)
// illustration :
// the time_consuming_function will be called only once in the loop, while cos is called 10 times
auto time_consuming_function=[](double x){std::cout<<"call time_consuming_function"<<std::endl;return 2*x;};
triqs::clef::make_expr(V) [i_] << cos( time_consuming_function(10) * i_ );
// If you insist using on more complex container ....
std::vector<std::vector<double>> W(3, std::vector<double>(5));
triqs::clef::make_expr(W)[i_] [j_] << i_ + cos( time_consuming_function(10) * j_ + i_);
// You can also put a CLEF expression in a std::function
// a function i -> 2*i +1
std::function<int(int)> f = i_ >> 2*i_ +1;
// a function (i,j) -> 2*i +j
std::function<double(int,int)> g = var(i_,j_) >> 2*i_ +j_;
// checking ...
std::cout<< "f(10) =" << f(10)<< " g(1,2) =" << g(1,2)<< std::endl;
// You can also use a Curry form : h is a function i-> j -> 2*i+ j
auto h = i_ >> (j_ >> 2*i_ +j_);
std::cout<< "h(1)(2) = " << h(1)(2) << std::endl;
// You an also use this to quickly write some lambda, as an alternative syntax to the C++ lambda
// with e.g. STL algorithms (with the advantage that the function is polymorphic !).
std::vector<int> v = {0,-1,2,-3,4,5,-6};
// replace all negative elements (i.e. those for which i -> (i<0) return true), by 0
std::replace_if(begin(v), end(v), i_ >> (i_<0), 0);
// for non believer, it really worked ...
for (auto const & x : v) std::cout <<x <<" "; std::cout << std::endl;
}
Functional programming techniques are now widely used. For example, boost::phoenix library
provides simple lambda techniques.
NPL is

View File

@ -1,226 +0,0 @@
.. highlight:: c
.. _callable_object:
Overloading functions and callable objects for clef expression arguments
=============================================================================
Given a callable object or a function, it is possible to overload it for clef expression arguments, returning a clef expression.
In all cases:
*Overloads that are activated iif at least one argument is a clef expression*.
Functions
------------
std math functions
^^^^^^^^^^^^^^^^^^^^^^^^
The overload is defined by clef automatically for usual functions :
.. compileblock::
#include <triqs/clef.hpp>
#include <iostream>
int main() {
triqs::clef::placeholder<3> x_;
std::cout << 2.0 + std::cos(2.0) << std::endl;
std::cout << eval( x_ + cos(x_), x_ = 2) << std::endl; // NB : note the absence of std::
}
Overloading a function for clef expressions arguments
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The `TRIQS_CLEF_MAKE_FNT_LAZY` macro defines the overload for clef expressions arguments of a function. Synopsis is ::
namespace triqs { namespace clef {
TRIQS_CLEF_MAKE_FNT_LAZY (function_to_make_lazy);
}}
For example:
.. compileblock::
#include <triqs/clef.hpp>
#include <iostream>
double foo(double x) { return x/2;}
int foo(int x) { return x*2;}
namespace triqs { namespace clef { TRIQS_CLEF_MAKE_FNT_LAZY (foo) ; }}
int main() {
triqs::clef::placeholder<3> x_;
std::cout << foo(2.0) << std::endl;
std::cout << eval( x_ + foo(x_), x_ = 3) << std::endl;
std::cout << eval( x_ + foo(x_), x_ = 3.5) << std::endl;
}
Note that :
* This overload **must** be defined in the triqs::clef namespace, since it is found by ADL.
* The function `foo` can have many overloads.
* The function foo can be a template, BUT then the template must be disabled for lazy expressions, as in ::
.. compileblock::
#include <triqs/clef.hpp>
#include <iostream>
template<typename T>
typename std::enable_if<!triqs::clef::is_any_lazy<T>::value,T>::type
foo (T const & x) { return x+1;}
namespace triqs { namespace clef { TRIQS_CLEF_MAKE_FNT_LAZY (foo) ; }}
int main() {
triqs::clef::placeholder<3> x_;
std::cout << foo(2.0) << std::endl;
std::cout << eval( x_ + foo(x_), x_ = 3) << std::endl;
std::cout << eval( x_ + foo(x_), x_ = 3.5) << std::endl;
}
Callable objects
--------------------
Similarly to functions, classes can define an `operator()` for lazy expressions arguments.
It is an ordinary operator() that must :
* Be enabled only when one argument is a clef expression
* Return a clef expression.
The function make_expr_call helps.
Object stored by copy (default)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The default behaviour is to store the object by copy in the expression tree...
.. compileblock::
#include <triqs/clef.hpp>
struct Obj {
double v; // put something in it
Obj(double v_): v(v_){} // constructor
// The "normal", non lazy call operator ....
double operator() (double x) const { return 10*x;}
// Call operator for const object
// make_expr_call creates a clef expression with a "call" node at the top
// calling this object on the arguments.
// Obj is stored by making a copy in the expression tree.
// NB : the make_expr_call trait enabled only if one of the arguments is lazy
// hence if none of the Args are clef expression, the template is disabled by SFINAE.
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<Obj,Args...>::type
operator()( Args&&... args ) const { return make_expr_call(* this,args...);}
// Just to print itself nicely in the expressions
friend std::ostream & operator<<(std::ostream & out, Obj const & x) { return out<<"Obj";}
};
int main() {
Obj f(7);
triqs::clef::placeholder<3> x_;
triqs::clef::placeholder<4> y_;
std::cout << "Clef expression : "<< f(y_) + 2*x_ << std::endl ;
std::cout << "Complete evaluation : "<< eval(f(x_) + 2*x_, x_=1) << std::endl ;
std::cout << "Partial evaluation : "<< eval(f(y_) + 2*x_, y_=1) << std::endl ;
std::cout << "Complete evalution : "<< eval(f(y_) + 2*x_, x_=3, y_=1) << std::endl ;
}
Object stored by reference
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Sometimes, one want to escape the copy of the object in the tree.
In that case, just use a std::reference_wrapper in place of the object.
You have then to guarantee that the object will live longer that the expression
that you form.
.. compileblock::
#include <triqs/clef.hpp>
struct Obj {
double v; // put something in it
Obj(double v_): v(v_){} // constructor
Obj(Obj const &) = delete; // a non copyable object
// The "normal", non lazy call operator ....
double operator() (double x) const { return 10*x;}
// Same as above, but now we stored a ref to the object and not a copy of the object.
// Reference are encapsulated in std::reference_wrapper (Cf C++ documentation).
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const Obj>,Args...>::type
operator()( Args&&... args ) const { return make_expr_call (std::ref(* this),args...);}
// The non const version (which then stores a non-const reference ....)
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<Obj>,Args...>::type
operator()( Args&&... args ) { return make_expr_call (std::ref(* this),args...);}
// Just to print itself nicely in the expressions
friend std::ostream & operator<<(std::ostream & out, Obj const & x) { return out<<"Obj";}
};
int main() {
Obj f(7);
triqs::clef::placeholder<3> x_;
triqs::clef::placeholder<4> y_;
std::cout << "Clef expression : "<< f(y_) + 2*x_ << std::endl ;
std::cout << "Complete evaluation : "<< eval(f(x_) + 2*x_, x_=1) << std::endl ;
std::cout << "Partial evaluation : "<< eval(f(y_) + 2*x_, y_=1) << std::endl ;
std::cout << "Complete evalution : "<< eval(f(y_) + 2*x_, x_=3, y_=1) << std::endl ;
}
.. note : one can of course replace the reference_wrapper by a view of the object, e.g....
NB: When non lazy operator() is already a template ?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Then it must be disabled for clef expression argument, using the trait ::
clef::is_any_lazy<T...> :: value // true iif one of the T is a clef expression
Example, derived from the previous one :
.. compileblock::
#include <triqs/clef.hpp>
#include <iostream>
struct Obj {
double v; // put something in it
Obj(double v_): v(v_){} // constructor
// The "normal", non lazy call operator is now a template
template <typename T>
typename std::enable_if<!triqs::clef::is_any_lazy<T>::value, T>::type // correct
// T operator() (T const & x) const { return 10*x;} would be ambiguous !
operator() (T const & x) const { return 10*x;}
// lazy expression
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<Obj,Args...>::type
operator()( Args&&... args ) const { return make_expr_call(* this,args...);}
// Just to print itself nicely in the expressions
friend std::ostream & operator<<(std::ostream & out, Obj const & x) { return out<<"Obj";}
};
int main() {
Obj f(7);
triqs::clef::placeholder<3> x_;
triqs::clef::placeholder<4> y_;
std::cout << "Clef expression : "<< f(y_) + 2*x_ << std::endl ;
std::cout << "Partial evaluation : "<< eval(f(y_) + 2*x_, y_=1) << std::endl ;
std::cout << "Complete evalution : "<< eval(f(y_) + 2*x_, x_=3, y_=1) << std::endl ;
}

View File

@ -1,16 +0,0 @@
.. highlight:: c
clef::function class
==========================
The class triqs::clef::function is similar to boost::function (std::function),
except that :
* it can be constructed from an expression and an ordered list of placeholders.
* it is `lazy-callable` and `lazy-assignable`
.. note::
It stores the expression polymorphically, by erasing its type. (You can put various expressions into it, cf below).
This might lead to some performance penalty in some case, even though tests do not show that at present...
Example of usage is given in :ref:`lazy_function_ex`.

View File

@ -0,0 +1,129 @@
.. highlight:: c
Overloading functions and methods for CLEF arguments
=====================================================
.. _overload_function:
Overloading functions
----------------------------
Given a function, it is possible to overload it for CLEF expression arguments, returning a CLEF expression
using the `TRIQS_CLEF_MAKE_FNT_LAZY` macro.
**Synopsis** ::
namespace triqs { namespace clef {
TRIQS_CLEF_MAKE_FNT_LAZY (function_to_make_lazy);
}}
For example:
.. compileblock::
#include <triqs/clef.hpp>
#include <iostream>
// a simple foo function
double foo(double x) { return x/2;}
int foo(int x) { return x*2;}
// a more complex case : bar is already a template
// we have to disable it for CLEF expression to avoid ambiguity
// C++14 clean syntax will be (using concepts)
// template<NotClefExpression T>
// T bar (T const & x) { return x+1;}
// C++11 workaround
template<typename T>
typename std::enable_if<!triqs::clef::is_clef_expression<T>::value,T>::type
bar (T const & x) { return x+1;}
namespace triqs { namespace clef { TRIQS_CLEF_MAKE_FNT_LAZY (foo) ; TRIQS_CLEF_MAKE_FNT_LAZY (bar) ; }}
int main() {
triqs::clef::placeholder<3> x_;
std::cout << foo(2.0)<<" "<<eval(x_ + foo(x_), x_ = 3)<<" "<<eval(x_ + foo(x_), x_ = 3.5) << std::endl;
std::cout << bar(2.0)<<" "<<eval(x_ + bar(x_), x_ = 3)<<" "<<eval(x_ + bar(x_), x_ = 3.5) << std::endl;
}
Note that :
* This overload **must** be defined in the triqs::clef namespace, since it is found by ADL.
* The function `foo` can have many overloads.
* The function `bar` can be a template, BUT then the template must be disabled for lazy expressions.
* The overload is already defined by clef for usual functions :
.. compileblock::
#include <triqs/clef.hpp>
#include <iostream>
int main() {
triqs::clef::placeholder<3> x_;
std::cout << 2.0 + std::cos(2.0) << std::endl;
std::cout << eval( x_ + cos(x_), x_ = 2) << std::endl; // NB : note the absence of std::
}
.. _callable_object:
Overloading operator() and other methods
---------------------------------------------------
Similarly to functions, classes can define an `operator()` for CLEF expressions arguments (or any other method).
It is an ordinary operator() that must :
* Be enabled only when one argument is a CLEF expression
* Return a CLEF expression.
Example :
.. compileblock::
#include <triqs/clef.hpp>
struct Obj {
double v; // put something in it
Obj(double v_): v(v_){} // constructor
Obj(Obj const &) = delete; // a non copyable object, to illustrate that we do NOT copy...
// The "normal", non CLEF call operator ....
double operator() (double x) const { return 10*x;}
// This macro implements properly an overload of the operator ()
TRIQS_CLEF_IMPLEMENT_LAZY_CALL();
// a method
double my_method(double x) { return 2*x;}
// CLEF overload
TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(Obj,my_method);
// Just to print itself nicely in the expressions
friend std::ostream & operator<<(std::ostream & out, Obj const & x) { return out<<"Obj";}
};
int main() {
Obj f(7);
triqs::clef::placeholder<1> x_; triqs::clef::placeholder<2> y_;
std::cout << "Clef expression : "<< f(y_) + 2*x_ << std::endl ;
std::cout << "Complete evaluation : "<< eval(f(x_) + 2*x_, x_=1) << std::endl ;
std::cout << "Partial evaluation : "<< eval(f(y_) + 2*x_, y_=1) << std::endl ;
std::cout << "Complete evalution : "<< eval(f(y_) + 2*x_, x_=3, y_=1) << std::endl<<std::endl ;
std::cout << "Clef expression : "<< f.my_method(y_) + 2*x_ << std::endl ;
std::cout << "Complete evaluation : "<< eval(f.my_method(x_) + 2*x_, x_=1) << std::endl ;
std::cout << "Partial evaluation : "<< eval(f.my_method(y_) + 2*x_, y_=1) << std::endl ;
std::cout << "Complete evalution : "<< eval(f.my_method(y_) + 2*x_, x_=3, y_=1) << std::endl ;
}
**NB** When the method or the non CLEF operator() is already a template,
it must be disabled for clef expression argument, using the trait ::
clef::is_clef_expression<T...> // true iif one of the T is a clef expression
as the `bar` function above.

View File

@ -1,67 +0,0 @@
#include <triqs/clef/clef.hpp>
#include <triqs/clef/io.hpp>
#define TEST(X) std::cout << BOOST_PP_STRINGIZE((X)) << " ---> "<< (X) <<std::endl;
struct F1{
double v;
F1(double v_): v(v_){}
F1(F1 const &) = delete; // non copyable
double operator() (double x) const { return 10*x;}
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const F1>,Args...>::type
operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);}
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<F1>,Args...>::type
operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);}
template<typename Fnt> friend void triqs_clef_auto_assign (F1 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
friend std::ostream & operator<<(std::ostream & out, F1 const & x) { return out<<"F1";}
};
struct F1b {
double v; std::shared_ptr<double> v_ptr;
F1b(double v_): v_ptr (new double(v_)) {v=v_;} // on purpose, I avoid adding a default constructor !
F1b (F1b const & x) { v_ptr = x.v_ptr; v = x.v; std::cerr<< " F1 COPY "<<std::endl;}
//F1b (F1b && x) { v_ptr = x.v_ptr; v = x.v; std::cerr<< " F1 COPY "<<std::endl;}
double operator() (double x) const { return 10*x;}
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<F1b,Args...>::type
operator()( Args&&... args ) { return triqs::clef::make_expr_call (*this,args...);}
template<typename Fnt> friend void triqs_clef_auto_assign (F1b & x, Fnt f) { (*(x.v_ptr))++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
friend std::ostream & operator<<(std::ostream & out, F1b const & x) { return out<<"F1b";}
};
struct F2 {
double v;
F2() {v=0;}
double operator()(double x, double y) const { return 10*x + y;}
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const F2>,Args...>::type
operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);}
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<F2>,Args...>::type
operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);}
template<typename Fnt> friend void triqs_clef_auto_assign (F2 const & x, Fnt f) { std::cerr<< " called F2 triqs_clef_auto_assign "<< f(10,20)<<std::endl;}
friend std::ostream & operator<<(std::ostream & out, F2 const & x) { return out<<"F2";}
};
using namespace triqs::clef;
triqs::clef::placeholder <1> x_;
triqs::clef::placeholder <2> y_;
triqs::clef::placeholder <3> z_;
namespace tql= triqs::clef;

1
test/speed/clef_common.hpp Symbolic link
View File

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

View File

@ -5,13 +5,7 @@ struct F7 {
F7(double v_): v(v_){}
double operator() (int i1, int i2, int i3, int i4, int i5, int i6, int i7 ) const { return 10*i1;}
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const F7>,Args...>::type
operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);}
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<F7>,Args...>::type
operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);}
TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F7);
template<typename Fnt> friend void triqs_clef_auto_assign (F7 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(1,2,3,4,5,6,7)<<std::endl;}
friend std::ostream & operator<<(std::ostream & out, F7 const & x) { return out<<"F7";}

View File

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

View File

@ -6,37 +6,17 @@ struct F1{
double v;
F1(double v_): v(v_){}
F1(F1 const &) = delete; // non copyable
F1(F1 &&x) : v(x.v) { std::cerr << "Moving F1 "<< v<<std::endl;}
double operator() (double x) const { return 10*x;}
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const F1>,Args...>::type
operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);}
TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F1);
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<F1>,Args...>::type
operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);}
template<typename Fnt> friend void triqs_clef_auto_assign (F1 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
template<typename Fnt> friend void triqs_clef_auto_assign (F1 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
friend std::ostream & operator<<(std::ostream & out, F1 const & x) { return out<<"F1";}
};
struct F1b {
double v; std::shared_ptr<double> v_ptr;
F1b(double v_): v_ptr (new double(v_)) {v=v_;} // on purpose, I avoid adding a default constructor !
F1b (F1b const & x) { v_ptr = x.v_ptr; v = x.v; std::cerr<< " F1 COPY "<<std::endl;}
//F1b (F1b && x) { v_ptr = x.v_ptr; v = x.v; std::cerr<< " F1 COPY "<<std::endl;}
double operator() (double x) const { return 10*x;}
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<F1b,Args...>::type
operator()( Args&&... args ) { return triqs::clef::make_expr_call (*this,args...);}
template<typename Fnt> friend void triqs_clef_auto_assign (F1b & x, Fnt f) { (*(x.v_ptr))++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
friend std::ostream & operator<<(std::ostream & out, F1b const & x) { return out<<"F1b";}
};
struct F2 {
@ -45,15 +25,10 @@ struct F2 {
double operator()(double x, double y) const { return 10*x + y;}
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const F2>,Args...>::type
operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);}
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<F2>,Args...>::type
operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);}
TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F2);
template<typename Fnt> friend void triqs_clef_auto_assign (F2 const & x, Fnt f) { std::cerr<< " called F2 triqs_clef_auto_assign "<< f(10,20)<<std::endl;}
friend std::ostream & operator<<(std::ostream & out, F2 const & x) { return out<<"F2";}
};

View File

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

View File

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

View File

@ -58,31 +58,25 @@ int main() {
{
// testing the LHS wrting on an object caught by ref
F1 f(7);
F1 f(7);
std::cerr << " operator(double) still ok "<< f(2) << std::endl;
std::cout<< " f.v before assign "<<f.v<<" "<< std::endl;
f(x_ ) << 8*x_ ;
//f(x_ + y_) = 8*x_ ;// leads to a compile error as expected
//f(x_ + y_) << 8*x_ ;// leads to a compile error as expected
// test.cpp:129:14: error: no viable overloaded '='
// f(x_ + y_) = 8*x_ ;
// f(x_ + y_) << 8*x_ ;
// ~~~~~~~~~~ ^ ~~~~
std::cout<< " f.v after assign "<<f.v<<" "<< std::endl;
std::cout<<"-------------"<<std::endl;
std::cerr <<F1{9}(2,x_, F1{2})<<std::endl;
auto expr = F1{9}(x_);
expr << 7*x_;
std::cerr << expr << std::endl ;
F1{9}(x_ ) << 8*x_ ;
std::cerr<<"-------------"<<std::endl;
}
{
// testing the LHS wrting on object caught by copy
F1b fb(7);
std::cout<< " fb.v before assign "<<fb.v<<" "<< *fb.v_ptr<< std::endl;
fb(x_ ) << 8*x_ ;
//f(x_ + y_) = 8*x_ ;// leads to a compile error as expected
// test.cpp:129:14: error: no viable overloaded '='
// f(x_ + y_) = 8*x_ ;
// ~~~~~~~~~~ ^ ~~~~
std::cout<< " fb.v after assign "<<fb.v<<" "<< *fb.v_ptr<< std::endl;
std::cout<<"-------------"<<std::endl;
}
{
// testing fnt of 2 variables
F2 ff;

View File

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

View File

@ -12,19 +12,19 @@ int main() {
V[0]=14; V[1]=2; V[2]=3;
std::cout<< "V = "<< V[0]<<" "<<V[1]<<" "<<V[2]<<std::endl;
TEST( tql::eval(lazy(V) [i_], i_=0));
TEST( tql::eval(make_expr(V) [i_], i_=0));
lazy(V) [i_] << i_ + 2;
make_expr(V) [i_] << i_ + 2;
std::cout<< "V = "<< V[0]<<" "<<V[1]<<" "<<V[2]<<std::endl;
lazy(W) [i_] << i_ + lazy(V)[i_];
make_expr(W) [i_] << i_ + make_expr(V)[i_];
std::cout<< "W = "<< W[0]<<" "<<W[1]<<" "<<W[2]<<std::endl;
std::vector< std::vector< int> > v2 (3, std::vector<int>(2));
lazy(v2)[i_][j_] << (i_ + j_ + 1);
make_expr(v2)[i_][j_] << (i_ + j_ + 1);
for (size_t u=0; u<v2.size(); ++u)
for (size_t up=0; up<v2[0].size(); ++up)

View File

@ -1,5 +1,5 @@
V = 14 2 3
(tql::eval(lazy(V) [i_], i_=0)) ---> 14
(tql::eval(make_expr(V) [i_], i_=0)) ---> 14
V = 2 3 4
W = 2 4 6
11

View File

@ -0,0 +1,37 @@
#include "./common.hpp"
struct AA{
double v;
AA(double v_): v(v_){}
AA(AA const &) = delete; // non copyable
AA(AA &&x) : v(x.v) { std::cerr << "Moving AA "<< std::endl;}
double operator() (double x) const { return 10*x;}
TRIQS_CLEF_IMPLEMENT_LAZY_CALL(AA);
template<typename Fnt> friend void triqs_clef_auto_assign (AA & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
friend std::ostream & operator<<(std::ostream & out, AA const & x) { return out<<"AA";}
double my_method(double x) { return 2*x;}
#ifndef TRIQS_COMPILER_OBSOLETE_GCC
TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(AA,my_method);
#else
TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(AA,my_method,double);
#endif
};
int main() {
AA f{8};
TEST(eval( f.my_method(x_), x_ = 10));
};

View File

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

View File

@ -13,15 +13,10 @@ struct F1{
F1(F1 const &) = delete; // non copyable
double operator() (double x) const { return 10*x;}
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<const F1>,Args...>::type
operator()( Args&&... args ) const { return make_expr_call (std::ref(*this),args...);}
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<std::reference_wrapper<F1>,Args...>::type
operator()( Args&&... args ) { return make_expr_call (std::ref(*this),args...);}
TRIQS_CLEF_IMPLEMENT_LAZY_CALL(F1);
template<typename Fnt> friend void triqs_clef_auto_assign (F1 & x, Fnt f) { x.v++; std::cerr<< " called triqs_clef_auto_assign "<< f(100)<<std::endl;}
friend std::ostream & operator<<(std::ostream & out, F1 const & x) { return out<<"F1";}
};

View File

@ -1,56 +1,39 @@
#include <triqs/clef.hpp>
#include <triqs/clef/io.hpp>
// a general implementation type for all domain and summation methods
template<typename Domain, typename Options> struct sum_impl;
struct Riemann{}; // one sum method
template<typename Domain> struct sum_impl<Domain, Riemann> {
template<typename Domain> struct sum_impl {
Domain d;
sum_impl(Domain const &d_):d(d_) {}
// Disabled when F is a lazy_expression
// C++14
// double operator() (NotClefExpression const & f) const { double s=0; for (int u=0; u<10; ++u) s += f(u/10.0); return s;}
// C++11 form
template <typename F>
typename std::enable_if< !triqs::clef::is_any_lazy <F>::value, double >::type
typename std::enable_if< !triqs::clef::is_clef_expression <F>::value, double >::type
operator() (F const & f) const { double s=0; for (int u=0; u<10; ++u) s += f(u/10.0); return s;}
// Defines operator(). Enabled iff one argument is a clef expression.
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<sum_impl,Args...>::type
operator()( Args&&... args ) const { return triqs::clef::make_expr_call (*this,args...);}
TRIQS_CLEF_IMPLEMENT_LAZY_CALL(sum_impl);
// How to print this object in the printing of clef expression
friend std::ostream & operator<<(std::ostream & out, sum_impl const & x) { return out<<"sum";}
};
template<typename Domain, typename Option>
sum_impl<Domain,Option> sum_functional (Domain && d, Option) {return d;}
//--------- MAIN ---------------------------------------
// a little factory ...
template<typename Domain> sum_impl<Domain> sum_functional (Domain d) {return {d};}
struct DOM{};
int main() {
// two placeholders
triqs::clef::placeholder <1> x_;
triqs::clef::placeholder <2> y_;
triqs::clef::placeholder <1> x_; triqs::clef::placeholder <2> y_;
DOM d;
// integrate_on_d is the integration functional
auto integrate_on_d = sum_functional(d);
DOM d; // a domain
// integrate_on_d is the integration (!) over d with Riemann method
auto integrate_on_d = sum_functional( d, Riemann());
// This is a simple application of the sum to a function
std::cout<< integrate_on_d( x_ >> 2*x_ + 1 ) << std::endl;
// This creates a clef expression of placeholder y_, waiting to make the sum
// Indeed the argument is a clef expression of y_ returning a function
// composed by integrate_on_d, it is a clef expression of y_ returning a double
std::cout<< integrate_on_d( x_ >> 2*x_ + 1 + y_ ) << std::endl;
// Of course this expression can be mixed with others...
std::cout<< y_ + 2* integrate_on_d( x_ >> 2*x_ + 1 + y_ ) << std::endl;
// and it can be evaluated
std::cout<< eval (y_ + 2* integrate_on_d( x_ >> 2*x_ + 1 + y_ ) ,y_ =0) << std::endl;
// A function y -> y_ + integrate (x -> 2*x + y)
auto e1 = y_ + integrate_on_d( x_ >> 2*x_ + y_ );
std::cout<< e1 << std::endl;
std::cout<< eval (e1 ,y_ =0) << std::endl;
}

View File

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

View File

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

View File

@ -10,9 +10,9 @@ int main() {
double pi = std::acos(-1);
std::vector<double> V(N);
// automatic assignment of vector and use of lazy math function
// automatic assignment of vector and use of make_expr math function
tql::placeholder <0> k_;
tql::lazy(V) [k_] << cos( (2* pi* k_)/ N );
tql::make_expr(V) [k_] << cos( (2* pi* k_)/ N );
// check result...
for (size_t u=0; u<V.size(); ++u)

View File

@ -232,6 +232,31 @@ namespace triqs { namespace arrays {
typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, StorageType::is_weak >::type
operator()() && { return *this; }
// Interaction with the CLEF library : calling with any clef expression as argument build a new clef expression
// NB : this is ok because indexmap_storage_pair has a shallow copy constructor ...
// Correction : no copy, just a ref...
// so A(i_) if A is an array will NOT copy the data....
template< typename... Args>
typename clef::_result_of::make_expr_call<indexmap_storage_pair const &,Args...>::type
operator()( Args&&... args ) const & {
static_assert(sizeof...(Args) <= indexmap_type::rank, "Incorrect number of variable in call");// not perfect : ellipsis ...
return make_expr_call(*this,args...);
}
template< typename... Args>
typename clef::_result_of::make_expr_call<indexmap_storage_pair &,Args...>::type
operator()( Args&&... args ) & {
static_assert(sizeof...(Args) <= indexmap_type::rank, "Incorrect number of variable in call");// not perfect : ellipsis ...
return make_expr_call(*this,args...);
}
template< typename... Args>
typename clef::_result_of::make_expr_call<indexmap_storage_pair,Args...>::type
operator()( Args&&... args ) && {
static_assert(sizeof...(Args) <= indexmap_type::rank, "Incorrect number of variable in call");// not perfect : ellipsis ...
return make_expr_call(std::move(*this),args...);
}
#else
template<typename... Args> // non const version
@ -258,18 +283,25 @@ namespace triqs { namespace arrays {
typename ISPViewType<value_type,domain_type::rank, OptionFlags, TraversalOrder, ViewTag, false >::type
operator()() { return *this; }
#endif
// Interaction with the CLEF library : calling with any clef expression as argument build a new clef expression
// NB : this is ok because indexmap_storage_pair has a shallow copy constructor ...
// Correction : no copy, just a ref...
// so A(i_) if A is an array will NOT copy the data....
template< typename... Args>
typename clef::result_of::make_expr_call<indexmap_storage_pair,Args...>::type
typename clef::_result_of::make_expr_call<indexmap_storage_pair const &,Args...>::type
operator()( Args&&... args ) const {
static_assert(sizeof...(Args) <= indexmap_type::rank, "Incorrect number of variable in call");// not perfect : ellipsis ...
return make_expr_call(*this,args...);
//return make_expr_call( view_type(*this),args...);
}
template< typename... Args>
typename clef::_result_of::make_expr_call<indexmap_storage_pair &,Args...>::type
operator()( Args&&... args ) {
static_assert(sizeof...(Args) <= indexmap_type::rank, "Incorrect number of variable in call");// not perfect : ellipsis ...
return make_expr_call(*this,args...);
}
#endif
template<typename Fnt> friend void triqs_clef_auto_assign (indexmap_storage_pair & x, Fnt f) { assign_foreach(x,f);}
// ------------------------------- Iterators --------------------------------------------

View File

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

View File

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

View File

@ -2,7 +2,7 @@
*
* TRIQS: a Toolbox for Research in Interacting Quantum Systems
*
* Copyright (C) 2012 by O. Parcollet
* Copyright (C) 2012-2013 by O. Parcollet
*
* TRIQS is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
@ -21,12 +21,13 @@
#ifndef TRIQS_CLEF_CORE_H
#define TRIQS_CLEF_CORE_H
#include <triqs/utility/first_include.hpp>
#include <triqs/utility/macros.hpp>
#include <triqs/utility/compiler_details.hpp>
#include <tuple>
#include <type_traits>
#include <functional>
#include <memory>
#include <complex>
#include <assert.h>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
@ -36,109 +37,130 @@
namespace triqs { namespace clef {
typedef unsigned long long ull_t;
template<typename T> struct remove_cv_ref : std::remove_cv< typename std::remove_reference<T>::type> {};
namespace tags { struct function_class{}; struct function{}; struct subscript{}; struct terminal{}; struct if_else{}; struct unary_op{}; struct binary_op{}; }
// Compute the type to put in the expression tree.
// If T is a lvalue reference, pack it into a reference_wrapper, unless force_copy_in_expr<T>::value == true
// If T is an rvalue reference, we store it as the type (using move semantics).
template<typename T> struct force_copy_in_expr : std::false_type{};
template<typename T> struct force_copy_in_expr<T const> : force_copy_in_expr<T>{};
template< class T > struct expr_storage_t {typedef T type;};
template< class T > struct expr_storage_t<T&> : std::conditional<force_copy_in_expr<T>::value, T ,std::reference_wrapper<T>>{};
template< class T > struct expr_storage_t<T&&> {typedef T type;};
/* ---------------------------------------------------------------------------------------------------
* Placeholder and corresponding traits
* --------------------------------------------------------------------------------------------------- */
template<int i, typename T> struct pair {
static constexpr int p = i;
typedef typename remove_cv_ref <T>::type value_type;
value_type const & r;
value_type const & rhs() const { return r;}
pair (T const & t) : r(t){}
};
template<int i, typename T> class pair; // forward
// a placeholder is an empty struct, labelled by an int.
template<int N> struct placeholder {
static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]");
static constexpr int index = N;
template <typename RHS> pair<N,RHS> operator = (RHS const & rhs) { return pair<N,RHS>(rhs);}
template <typename RHS> pair<N,RHS> operator = (RHS && rhs) { return {std::forward<RHS>(rhs)};}
};
// 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 {};
template<int N> struct is_placeholder <placeholder <N> > : std::true_type {};
// ph_set is a trait that given a pack of type, returns the set of placeholders they contain
// it returns a int in binary coding : bit N in the int is 1 iif at least one T is lazy and contains placeholder<N>
template<typename... T> struct ph_set;
template<typename T0, typename... T> struct ph_set<T0,T...>{static constexpr ull_t value= ph_set<T0>::value| ph_set<T...>::value;};
template<typename T> struct ph_set<T> {static constexpr ull_t value= 0;};
template<int N> struct ph_set<placeholder<N>> {static constexpr ull_t value= 1ull<<N;};
template<int i, typename T> struct ph_set<pair<i,T> > : ph_set<placeholder<i>>{};
/* ---------------------------------------------------------------------------------------------------
* Detect if an object is a lazy expression
* --------------------------------------------------------------------------------------------------- */
template<typename... Args> struct is_any_lazy : std::false_type {};
template<int N> struct is_any_lazy <placeholder <N> > : std::true_type {};
template <typename T> struct is_any_lazy< T > : std::false_type {};
template <typename T> struct is_any_lazy< T&& > : is_any_lazy<T> {};
template <typename T> struct is_any_lazy< T& > : is_any_lazy<T> {};
template <typename T> struct is_any_lazy< T const > : is_any_lazy<T> {};
template<typename T, typename... Args> struct is_any_lazy<T, Args...> :
// in_any_lazy : trait to detect if any of Args is a lazy expression
template<typename... Args> struct is_any_lazy : std::false_type {};
template<int N> struct is_any_lazy <placeholder <N> > : std::true_type {};
template <typename T> struct is_any_lazy< T > : std::false_type {};
template <typename T> struct is_any_lazy< T&& > : is_any_lazy<T> {};
template <typename T> struct is_any_lazy< T& > : is_any_lazy<T> {};
template <typename T> struct is_any_lazy< T const > : is_any_lazy<T> {};
template<typename T, typename... Args> struct is_any_lazy<T, Args...> :
std::integral_constant<bool, is_any_lazy<T>::value || is_any_lazy<Args...>::value> {};
// a trait that checks the type are value i.e. no &, &&
template<typename... T> struct has_no_ref : std::true_type {};
template<typename T0, typename... T> struct has_no_ref<T0,T...> : std::integral_constant<bool, !(std::is_reference<T0>::value)&& has_no_ref<T...>::value> {};
template<typename T>
constexpr bool ClefExpression() { return is_any_lazy<T>::value;}
/* ---------------------------------------------------------------------------------------------------
template<typename T> struct is_clef_expression : is_any_lazy<T>{};
/* ---------------------------------------------------------------------------------------------------
* Node of the expression tree
* --------------------------------------------------------------------------------------------------- */
template<typename Tag, typename... T> struct expr {
static_assert( has_no_ref<T...>::value , "Internal error : expr childs can not be reference ");
typedef std::tuple< T ...> childs_t;
// T can be U, U & (a reference or a value).
typedef std::tuple<T...> childs_t;
childs_t childs;
expr(expr const & x) = default;
expr(expr && x) : childs(std::move(x.childs)) {}
template<typename... Args> explicit expr(Tag, Args&&...args) : childs(std::forward<Args>(args)...) {}
template< typename Args >
expr<tags::subscript, expr, typename remove_cv_ref<Args>::type > operator[](Args && args) const
{ return expr<tags::subscript, expr, typename remove_cv_ref<Args>::type> (tags::subscript(), *this,std::forward<Args>(args));}
expr(expr && x) noexcept : childs(std::move(x.childs)) {}
// a constructor with the Tag make it unambiguous with other constructors...
template<typename... Args> expr(Tag, Args&&...args) : childs(std::forward<Args>(args)...) {}
// [] returns a new lazy expression, with one more layer
template<typename Args>
expr<tags::subscript, expr, typename expr_storage_t<Args>::type > operator[](Args && args) const
{ return {tags::subscript(), *this,std::forward<Args>(args)};}
// () also ...
template< typename... Args >
expr<tags::function, expr, typename remove_cv_ref<Args>::type...> operator()(Args && ... args) const
{ return expr<tags::function, expr, typename remove_cv_ref<Args>::type...>(tags::function(), *this,std::forward<Args>(args)...);}
// only f(i,j) = expr is allowed, in case where f is a clef::function
// otherwise use the << operator
expr<tags::function, expr, typename expr_storage_t<Args>::type...> operator()(Args && ... args) const
{ return {tags::function(), *this,std::forward<Args>(args)...};}
// assignement is in general deleted
expr & operator= (expr const &) = delete; // no ordinary assignment
expr & operator= (expr &&) = default; // move assign ok
// however, this is ok in the case f(i,j) = expr, where f is a clef::function
template<typename RHS, typename CH = childs_t>
typename std::enable_if<std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>::value>::type
ENABLE_IF(std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>)
operator= (RHS const & rhs) { *this << rhs;}
template<typename RHS, typename CH = childs_t>
typename std::enable_if<!std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>::value>::type
DISABLE_IF(std::is_base_of<tags::function_class, typename std::tuple_element<0,CH>::type>)
operator= (RHS const & rhs) = delete;
expr & operator= (expr const & ) = delete; // no ordinary copy
};
// set some traits
template<typename Tag, typename... T> struct ph_set< expr<Tag,T... > > : ph_set<T...> {};
template<typename Tag, typename... T> struct is_any_lazy< expr<Tag,T... > >: std::true_type {};
// if we want that subexpression are copied ?
template<typename Tag, typename... T> struct force_copy_in_expr< expr<Tag,T... > > : std::true_type{};
/* ---------------------------------------------------------------------------------------------------
* The basic operations put in a template....
* --------------------------------------------------------------------------------------------------- */
template<typename Tag> struct operation;
// a little function to clean the reference_wrapper
template<typename U> U & _cl(U & x) { return x;}
template<typename U> U & _cl(std::reference_wrapper<U> x) { return x.get();}
/// Terminal
template<> struct operation<tags::terminal> { template<typename L> L operator()(L&& l) const { return std::forward<L>(l);} };
/// Function call
template<> struct operation<tags::function> {
template<typename F, typename... Args> auto operator()(F const & f, Args const & ... args) const -> decltype(f(args...)) { return f(args...);}
template<typename F, typename... Args> auto operator()(std::reference_wrapper<F> const &f, Args const & ... args) const -> decltype(f.get()(args...)) { return f.get()(args...);}
template<typename F, typename... Args> auto operator()(F const & f, Args const & ... args) const DECL_AND_RETURN(_cl(f)(_cl(args)...));
};
/// [ ] Call
template<> struct operation<tags::subscript> {
template<typename F, typename Args> auto operator()(F const & f, Args const & args) const -> decltype(f[args]) { return f[args];}
template<typename F, typename Args> auto operator()(std::reference_wrapper<F> const &f, Args const & args) const -> decltype(f.get()[args]) { return f.get()[args];}
template<typename F, typename Args> auto operator()(F const & f, Args const & args) const DECL_AND_RETURN(_cl(f)[_cl(args)]);
};
// all binary operators....
#define TRIQS_CLEF_OPERATION(TAG,OP)\
namespace tags { struct TAG : binary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\
template<> struct operation<tags::TAG> {\
template<typename L, typename R> auto operator()(L const & l, R const & r) const -> decltype(l OP r) { return l OP r;}\
template<typename L, typename R> auto operator()(L const & l, R const & r) const DECL_AND_RETURN ( _cl(l) OP _cl(r));\
};\
template<typename L, typename R>\
typename std::enable_if<is_any_lazy<L,R>::value, expr<tags::TAG,typename remove_cv_ref<L>::type,typename remove_cv_ref<R>::type> >::type \
operator OP (L && l, R && r) { return expr<tags::TAG,typename remove_cv_ref<L>::type,typename remove_cv_ref<R>::type> (tags::TAG(),std::forward<L>(l),std::forward<R>(r));}\
typename std::enable_if<is_any_lazy<L,R>::value, expr<tags::TAG,typename expr_storage_t<L>::type,typename expr_storage_t<R>::type> >::type \
operator OP (L && l, R && r) { return {tags::TAG(),std::forward<L>(l),std::forward<R>(r)};}\
TRIQS_CLEF_OPERATION(plus, +);
TRIQS_CLEF_OPERATION(minus, -);
@ -155,11 +177,11 @@ namespace triqs { namespace clef {
#define TRIQS_CLEF_OPERATION(TAG,OP)\
namespace tags { struct TAG : unary_op { static const char * name() { return BOOST_PP_STRINGIZE(OP);} };}\
template<> struct operation<tags::TAG> {\
template<typename L> auto operator()(L const & l) const -> decltype(OP l) { return OP l;}\
template<typename L> auto operator()(L const & l) const DECL_AND_RETURN (OP _cl(l));\
};\
template<typename L>\
typename std::enable_if<is_any_lazy<L>::value, expr<tags::TAG,typename remove_cv_ref<L>::type> >::type \
operator OP (L && l) { return expr<tags::TAG,typename remove_cv_ref<L>::type> (tags::TAG(),std::forward<L>(l));}\
typename std::enable_if<is_any_lazy<L>::value, expr<tags::TAG,typename expr_storage_t<L>::type> >::type \
operator OP (L && l) { return {tags::TAG(),std::forward<L>(l)};}\
TRIQS_CLEF_OPERATION(negate, -);
TRIQS_CLEF_OPERATION(loginot, !);
@ -167,17 +189,12 @@ namespace triqs { namespace clef {
/// the only ternary node : expression if
template<> struct operation<tags::if_else> {
template<typename C, typename A, typename B> auto operator()(C const & c, A const & a, B const & b) const -> decltype((c?a:b)) {
//static_assert(std::is_same<typename remove_cv_ref<A>::type,typename remove_cv_ref<B>::type>::value, "Expression if : evaluation type must be the same");
return (c ? a: b);
}
template<typename C, typename A, typename B> auto operator()(C const & c, A const & a, B const & b) const DECL_AND_RETURN (_cl(c) ? _cl(a): _cl(b));
};
// operator is : if_else( Condition, A, B)
template<typename C, typename A, typename B>
expr<tags::if_else,typename remove_cv_ref<C>::type,typename remove_cv_ref<A>::type,typename remove_cv_ref<B>::type>
if_else(C && c, A && a, B && b) {
return expr<tags::if_else,typename remove_cv_ref<C>::type,typename remove_cv_ref<A>::type,typename remove_cv_ref<B>::type>
(tags::if_else(),std::forward<C>(c),std::forward<A>(a),std::forward<B>(b));}
expr<tags::if_else,typename expr_storage_t<C>::type,typename expr_storage_t<A>::type,typename expr_storage_t<B>::type>
if_else(C && c, A && a, B && b) { return {tags::if_else(),std::forward<C>(c),std::forward<A>(a),std::forward<B>(b)};}
/* ---------------------------------------------------------------------------------------------------
* Evaluation of the expression tree.
@ -186,18 +203,18 @@ namespace triqs { namespace clef {
template<typename Tag, bool IsLazy, typename... Args> struct operation2;
template<typename Tag, typename... Args> struct operation2<Tag, true, Args...> {
typedef expr<Tag,typename remove_cv_ref<Args>::type ...> rtype;
rtype operator()(Args && ... args) const {return rtype (Tag(), std::forward<Args>(args)...);}
rtype operator()(Args const & ... args) const {return rtype {Tag(), args...};}
};
template<typename Tag, typename... Args> struct operation2<Tag, false, Args...> {
typedef typename std::remove_reference<typename std::result_of<operation<Tag>(Args...)>::type>::type rtype;
// remove the reference because of ternary if_else in which decltype returns a ref...
rtype operator()(Args const & ... args) const {return operation<Tag>()(args...); }
rtype operator()(Args const & ... args) const {return operation<Tag>()(args...); }
};
// Generic case : do nothing (for the leaf of the tree except placeholder)
template<typename T, typename ... Pairs> struct evaluator{
typedef T rtype;
rtype operator()( T const & k, Pairs const &... pairs) {return k;}
rtype operator()(T const & k, Pairs const &... pairs) {return k;}
};
// placeholder
@ -207,40 +224,53 @@ namespace triqs { namespace clef {
rtype operator()(placeholder<N>, pair<i,T> const &, Pairs const& ... pairs) { return eval_t()(placeholder<N>(), pairs...);}
};
template<int N, typename T, typename... Pairs> struct evaluator< placeholder<N>, pair<N,T>, Pairs... > {
typedef typename pair<N,T>::value_type const & rtype;
rtype operator()(placeholder<N>, pair<N,T> const & p, Pairs const& ...) { return p.r;}
typedef T const & rtype;
//typedef typename pair<N,T>::value_type const & rtype;
rtype operator()(placeholder<N>, pair<N,T> const & p, Pairs const& ...) { return p.rhs;}
};
// general expr node
template<typename Tag, typename... Childs, typename... Pairs> struct evaluator<expr<Tag, Childs...>, Pairs...> {
typedef operation2<Tag, is_any_lazy<typename evaluator<Childs, Pairs...>::rtype... >::value, typename evaluator<Childs, Pairs...>::rtype... > OPTYPE;
typedef typename OPTYPE::rtype rtype;
// first done manually for clearer error messages ...
template< int arity = sizeof...(Childs)>
typename std::enable_if< arity==1, rtype>::type
operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const
{ return OPTYPE()(eval(std::get<0>(ex.childs),pairs...) );}
template< int arity = sizeof...(Childs)>
typename std::enable_if< arity==2, rtype>::type
operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const
{ return OPTYPE()(eval(std::get<0>(ex.childs),pairs...),eval(std::get<1>(ex.childs),pairs...) );}
#define AUX(z,p,unused) eval(std::get<p>(ex.childs),pairs...)
#define IMPL(z, NN, unused) \
template< int arity = sizeof...(Childs)>\
typename std::enable_if< arity==NN, rtype>::type\
operator()(expr<Tag, Childs...> const & ex, Pairs const & ... pairs) const\
{ return OPTYPE()(BOOST_PP_ENUM(NN,AUX,nil));}
BOOST_PP_REPEAT_FROM_TO(1,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil);
BOOST_PP_REPEAT_FROM_TO(3,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil);
#undef AUX
#undef IMPL
};
#ifdef TRIQS_CLEF_EVAL_SHORT_CIRCUIT
// A short circuit if intersection of ph and is 0, no need to evaluate the whole tree......
// Seems useless, && the second eval is not correct if hte expression is a terminal.
template<typename T, typename... Pairs>
typename std::enable_if< (ph_set<T>::value & ph_set<Pairs...>::value) !=0, typename evaluator<T,Pairs...>::rtype > ::type
eval (T const & ex, Pairs const &... pairs) { return evaluator<T, Pairs...>()(ex, pairs...); }
template<typename T, typename... Pairs>
typename std::enable_if< (ph_set<T>::value & ph_set<Pairs...>::value) ==0, T const &> ::type
eval (T const & ex, Pairs const &... pairs) { return ex;}
#else
// The general eval function for expressions
template<typename T, typename... Pairs>
typename evaluator<T,Pairs...>::rtype
eval (T const & ex, Pairs const &... pairs) { return evaluator<T, Pairs...>()(ex, pairs...); }
#ifdef TRIQS_SHORT_CIRCUIT_NOT_IMPLEMENTED
// A short circuit if intersection of ph and is 0, no need to evaluate the whole tree......
template<typename T, typename... Pairs>
template<typename Tag, typename... Childs, typename... Pairs>
typename std::enable_if< (ph_set<Childs...>::value & ph_set<Pairs...>::value) !=0, typename evaluator<expr<Tag,Childs...>,Pairs...>::rtype > ::type
eval (expr<Tag,Childs...> const & ex, Pairs const &... pairs) { return evaluator<expr<Tag,Childs...>, Pairs...>()(ex, pairs...); }
template<typename Tag, typename... Childs, typename... Pairs>
typename std::enable_if< (ph_set<Childs...>::value & ph_set<Pairs...>::value) ==0, expr<Tag,Childs...> > ::type
eval (expr<Tag,Childs...> const & ex, Pairs const &... pairs) { return ex; }
#endif
/* ---------------------------------------------------------------------------------------------------
@ -252,29 +282,30 @@ namespace triqs { namespace clef {
make_fun_impl(Expr const & ex_) : ex(ex_) {}
// gcc 4.6 crashes (!!!) on the first variant
#define TRIQS_WORKAROUND_GCC46BUG
#ifndef TRIQS_WORKAROUND_GCC46BUG
#ifndef TRIQS_COMPILER_OBSOLETE_GCC
template<typename... Args>
typename evaluator<Expr,pair<Is,Args>...>::rtype
operator()(Args const &... args) const
{ return evaluator<Expr,pair<Is,Args>...>() ( ex, pair<Is,Args>(args)...); }
operator()(Args &&... args) const
{ return evaluator<Expr,pair<Is,Args>...>() ( ex, pair<Is,Args>{std::forward<Args>(args)}...); }
#else
template<typename... Args> struct __eval {
typedef evaluator<Expr,pair<Is,Args>...> eval_t;
typedef typename eval_t::rtype rtype;
rtype operator()(Expr const &ex , Args const &... args) const { return eval_t() ( ex, pair<Is,Args>(args)...); }
rtype operator()(Expr const &ex , Args &&... args) const { return eval_t() ( ex, pair<Is,Args>{std::forward<Args>(args)}...); }
};
template<typename... Args>
typename __eval<Args...>::rtype operator()(Args const &... args) const { return __eval<Args...>() ( ex, args...); }
typename __eval<Args...>::rtype operator()(Args &&... args) const { return __eval<Args...>() ( ex, std::forward<Args>(args)...); }
#endif
};
// values of the ph, excluding the Is ...
template<ull_t x, int... Is> struct ph_filter;
template<ull_t x, int I0, int... Is> struct ph_filter<x,I0,Is...> { static constexpr ull_t value = ph_filter<x,Is...>::value & (~ (1ull<<I0));};
template<ull_t x> struct ph_filter<x> { static constexpr ull_t value = x; };
template< typename Expr, int... Is> struct ph_set<make_fun_impl<Expr,Is...> > { static constexpr ull_t value = ph_filter <ph_set<Expr>::value, Is...>::value;};
template< typename Expr, int... Is> struct is_any_lazy<make_fun_impl<Expr,Is...> > : std::integral_constant<bool,ph_set<make_fun_impl<Expr,Is...>>::value !=0>{};
template< typename Expr, int... Is> struct force_copy_in_expr<make_fun_impl<Expr,Is...> > : std::true_type{};
template< typename Expr, int... Is,typename... Pairs> struct evaluator<make_fun_impl<Expr,Is...>, Pairs...> {
typedef evaluator<Expr,Pairs...> e_t;
@ -283,22 +314,28 @@ namespace triqs { namespace clef {
};
template< typename Expr, typename ... Phs>
make_fun_impl<typename std::remove_cv<typename std::remove_reference<Expr>::type>::type,Phs::index...>
make_fun_impl<typename remove_cv_ref <Expr>::type,Phs::index...>
make_function(Expr && ex, Phs...) { return {ex}; }
namespace result_of {
template< typename Expr, typename ... Phs> struct make_function {
typedef make_fun_impl<typename std::remove_cv<typename std::remove_reference<Expr>::type>::type,Phs::index...> type;
typedef make_fun_impl<typename remove_cv_ref<Expr>::type,Phs::index...> type;
};
}
template<int ... N>
std::tuple<placeholder<N>...> var( placeholder<N> ...) { return std::make_tuple(placeholder<N>()...);}
template<typename Expr, int ... N>
auto operator >> (std::tuple<placeholder<N>...>, Expr const & ex) DECL_AND_RETURN( make_function(ex, placeholder<N>()...));
/* --------------------------------------------------------------------------------------------------
* make_function
* x_ >> expression is the same as make_function(expression,x)
* --------------------------------------------------------------------------------------------------- */
template <int N, typename Expr>
make_fun_impl<Expr,N > operator >> ( placeholder<N> p, Expr&& ex) { return {ex}; }
make_fun_impl<Expr,N > operator >> (placeholder<N> p, Expr&& ex) { return {ex}; }
/* ---------------------------------------------------------------------------------------------------
* Auto assign for ()
@ -315,7 +352,7 @@ namespace triqs { namespace clef {
template<typename Tag, typename... Childs, typename RHS>
void triqs_clef_auto_assign (expr<Tag,Childs...> && ex, RHS const & rhs) { ex << rhs;}
template<typename Tag, typename... Childs, typename RHS>
template<typename Tag, typename... Childs, typename RHS>
void triqs_clef_auto_assign (expr<Tag,Childs...> const & ex, RHS const & rhs) { ex << rhs;}
// The case A(x_,y_) = RHS : we form the function (make_function) and call auto_assign (by ADL)
@ -327,6 +364,10 @@ namespace triqs { namespace clef {
void operator<<(expr<tags::function, F, placeholder<Is>...> const & ex, RHS && rhs) {
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
}
template<typename F, typename RHS, int... Is>
void operator<<(expr<tags::function, F, placeholder<Is>...> & ex, RHS && rhs) {
triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
}
// any other case e.g. f(x_+y_) = RHS etc .... which makes no sense : compiler will stop
template<typename F, typename RHS, typename... T>
@ -348,6 +389,9 @@ namespace triqs { namespace clef {
{ triqs_clef_auto_assign_subscript(std::get<0>(t.childs),std::forward<F>(f));}
// auto assign of an expr ? (for chain calls) : just reuse the same operator
template<typename Tag, typename... Childs, typename RHS>
void triqs_clef_auto_assign_subscript (expr<Tag,Childs...> && ex, RHS const & rhs) { ex << rhs;}
template<typename Tag, typename... Childs, typename RHS>
void triqs_clef_auto_assign_subscript (expr<Tag,Childs...> const & ex, RHS const & rhs) { ex << rhs;}
@ -356,45 +400,58 @@ namespace triqs { namespace clef {
void operator<<(expr<tags::subscript, F, placeholder<Is>...> const & ex, RHS && rhs) {
triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
}
template<typename F, typename RHS, typename... T>
template<typename F, typename RHS, int... Is>
void operator<<(expr<tags::subscript, F, placeholder<Is>...> && ex, RHS && rhs) {
triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward<RHS>(rhs), placeholder<Is>()...));
}
template<typename F, typename RHS, typename... T>
void operator<<(expr<tags::subscript, F, T...> && ex, RHS && rhs) = delete;
template<typename F, typename RHS, typename... T>
void operator<<(expr<tags::subscript, F, T...> const & ex, RHS && rhs) = delete;
/* --------------------------------------------------------------------------------------------------
* Create a terminal node of an object. The reference is wrapped in a reference_wrapper...
* Create a terminal node of an object. the from clone version force copying the object
* --------------------------------------------------------------------------------------------------- */
template<typename T> expr<tags::terminal,typename remove_cv_ref<T>::type >
make_expr(T && x){ return expr<tags::terminal,typename remove_cv_ref<T>::type >(tags::terminal(), std::forward<T>(x));}
// make a node with the ref, unless it is an rvalue (which is moved).
template<typename T> expr<tags::terminal,typename expr_storage_t<T>::type >
make_expr(T && x){ return {tags::terminal(), std::forward<T>(x)};}
template<typename T> auto lazy (T && x) -> decltype (make_expr(std::ref(x))) { return make_expr(std::ref(x)); }
// make a node from a copy of the object
template<typename T> expr<tags::terminal,typename remove_cv_ref<T>::type >
make_expr_from_clone(T && x){ return {tags::terminal(), std::forward<T>(x)};}
/* --------------------------------------------------------------------------------------------------
* Create a call node of an object
* The object can be kept as a : a ref, a copy, a view
* --------------------------------------------------------------------------------------------------- */
namespace result_of {
template<typename T> struct arity { static constexpr int value =-1;};
namespace _result_of {
template< typename Obj, typename... Args > struct make_expr_call :
std::enable_if< is_any_lazy<Args...>::value, expr<tags::function,typename remove_cv_ref<Obj>::type, typename remove_cv_ref<Args>::type ...> > {};
std::enable_if< is_any_lazy<Args...>::value, expr<tags::function,typename expr_storage_t<Obj>::type, typename expr_storage_t<Args>::type ...> > {
static_assert (((arity<Obj>::value==-1) || (arity<Obj>::value == sizeof...(Args))), "Object called with a wrong number of arguments");
};
}
template< typename Obj, typename... Args >
typename result_of::make_expr_call<Obj,Args...>::type
make_expr_call(Obj&& obj, Args &&... args)
{ return typename result_of::make_expr_call<Obj,Args...>::type (tags::function(),std::forward<Obj>(obj), std::forward<Args>(args)...);}
typename _result_of::make_expr_call<Obj,Args...>::type
make_expr_call(Obj&& obj, Args &&... args) { return {tags::function(),std::forward<Obj>(obj), std::forward<Args>(args)...};}
/* --------------------------------------------------------------------------------------------------
* Create a [] call (subscript) node of an object
* The object can be kept as a : a ref, a copy, a view
* --------------------------------------------------------------------------------------------------- */
namespace result_of {
namespace _result_of {
template< typename Obj, typename Arg> struct make_expr_subscript :
std::enable_if< is_any_lazy<Arg>::value, expr<tags::subscript,typename remove_cv_ref<Obj>::type, typename remove_cv_ref<Arg>::type> > {};
std::enable_if< is_any_lazy<Arg>::value, expr<tags::subscript,typename expr_storage_t<Obj>::type, typename expr_storage_t<Arg>::type> > {};
}
template< typename Obj, typename Arg>
typename result_of::make_expr_subscript<Obj,Arg>::type
make_expr_subscript(Obj&& obj, Arg && arg)
{ return typename result_of::make_expr_subscript<Obj,Arg>::type (tags::subscript(),std::forward<Obj>(obj), std::forward<Arg>(arg));}
typename _result_of::make_expr_subscript<Obj,Arg>::type
make_expr_subscript(Obj&& obj, Arg && arg) { return {tags::subscript(),std::forward<Obj>(obj), std::forward<Arg>(arg)};}
/* --------------------------------------------------------------------------------------------------
* function class : stores any expression polymorphically
@ -408,23 +465,30 @@ namespace triqs { namespace clef {
mutable std::shared_ptr <void> _exp; // CLEAN THIS MUTABLE ?
mutable std::shared_ptr < std_function_type > _fnt_ptr;
public:
function():_fnt_ptr(new std_function_type ()){}
function():_fnt_ptr{std::make_shared<std_function_type> ()}{}
template<typename Expr, typename... X>
explicit function(Expr const & _e, X... x) : _exp(new Expr(_e)),_fnt_ptr(new std_function_type(make_function(_e, x...))){}
ReturnType operator()(T const &... t) const { return (*_fnt_ptr)(t...);}
#ifndef TRIQS_COMPILER_OBSOLETE_GCC
template< typename... Args>
typename triqs::clef::result_of::make_expr_call<function,Args...>::type
operator()( Args&&... args ) const { return triqs::clef::make_expr_call (*this,args...);}
auto operator()( Args&&... args ) const DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));
#else
template< typename... Args>
typename _result_of::make_expr_call<function const & ,Args...>::type
operator()( Args&&... args ) const { return make_expr_call (*this,args...);}
#endif
template<typename RHS> friend void triqs_clef_auto_assign (function const & x, RHS rhs) {
* (x._fnt_ptr) = std_function_type (rhs);
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
* TRIQS_CLEF_MAKE_FNT_LAZY (Arity,FunctionName ) : creates a new function in the triqs::lazy namespace
@ -433,11 +497,54 @@ namespace triqs { namespace clef {
* --------------------------------------------------------------------------------------------------- */
#define TRIQS_CLEF_MAKE_FNT_LAZY(name)\
struct name##_lazy_impl { \
template<typename... A> auto operator()(A&&... a) const -> decltype (name(std::forward<A>(a)...)) { return name(std::forward<A>(a)...); }\
template<typename... A> auto operator()(A&&... a) const DECL_AND_RETURN (name(std::forward<A>(a)...));\
};\
template< typename... A> \
typename triqs::clef::result_of::make_expr_call<name##_lazy_impl,A...>::type name( A&& ... a) { return make_expr_call(name##_lazy_impl(),a...);}
auto name( A&& ... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(),std::forward<A>(a)...));
#ifndef TRIQS_COMPILER_OBSOLETE_GCC
#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY,name)\
struct __clef_lazy_method_impl_##name { \
TY * _x;\
template<typename... A> auto operator()(A&&... a) const DECL_AND_RETURN ((*_x).name(std::forward<A>(a)...));\
friend std::ostream & operator<<(std::ostream & out, __clef_lazy_method_impl_##name const & x) { return out<<BOOST_PP_STRINGIZE(TY)<<"."<<BOOST_PP_STRINGIZE(name);}\
};\
template< typename... A> \
auto name( A&& ... a) DECL_AND_RETURN (make_expr_call(__clef_lazy_method_impl_##name{this},std::forward<A>(a)...));
#define TRIQS_CLEF_IMPLEMENT_LAZY_CALL(...)\
template< typename... Args>\
auto operator()(Args&&... args ) const & DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));\
\
template< typename... Args>\
auto operator()(Args&&... args ) & DECL_AND_RETURN(make_expr_call (*this,std::forward<Args>(args)...));\
\
template< typename... Args>\
auto operator()(Args&&... args ) && DECL_AND_RETURN(make_expr_call (std::move(*this),std::forward<Args>(args)...));\
#else
#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY,name,RETURN_TYPE)\
struct __clef_lazy_method_impl_##name { \
TY * _x;\
template<typename... A> RETURN_TYPE operator()(A&&... a) const {return ((*_x).name(std::forward<A>(a)...));}\
friend std::ostream & operator<<(std::ostream & out, __clef_lazy_method_impl_##name const & x) { return out<<BOOST_PP_STRINGIZE(TY)<<"."<<BOOST_PP_STRINGIZE(name);}\
};\
template< typename... A> \
typename _result_of::make_expr_call<__clef_lazy_method_impl_##name, A...>::type\
name( A&& ... a) {return make_expr_call(__clef_lazy_method_impl_##name{this},std::forward<A>(a)...);}
#define TRIQS_CLEF_IMPLEMENT_LAZY_CALL(TY)\
template< typename... Args>\
typename triqs::clef::_result_of::make_expr_call<TY const &,Args...>::type\
operator()(Args&&... args ) const {return make_expr_call (*this,std::forward<Args>(args)...);}\
\
template< typename... Args>\
typename triqs::clef::_result_of::make_expr_call<TY &,Args...>::type\
operator()(Args&&... args ) {return make_expr_call (*this,std::forward<Args>(args)...);}
#endif
}} // namespace triqs::clef
#endif

View File

@ -31,6 +31,7 @@ namespace triqs { namespace clef {
template<int N> std::ostream &operator <<(std::ostream &sout, placeholder<N> ){return sout << "_"<<N ; }
template<typename T> std::ostream & operator<<(std::ostream & out, std::reference_wrapper<T> const & x) { return out<< x.get(); }
//template<typename T> std::ostream & operator<<(std::ostream & out, std::reference_wrapper<T> const & x) { return out<< "["<<x.get()<<"]"; }
inline std::ostream & variadic_print(std::ostream& out) { return out; }
template<typename T0, typename... T> std::ostream & variadic_print(std::ostream& out, T0&& t0, T&&... t)

View File

@ -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)...); }
// Interaction with the CLEF library : calling the gf with any clef expression as argument build a new clef expression
//template<typename Arg0, typename ...Args>
// auto operator()(Arg0 arg0, Args... args) const DECL_AND_RETURN( clef::make_expr_call(view_type(*this),arg0, args...));
//template<typename Arg0, typename ...Args>
// auto operator()(Arg0 arg0, Args... args) DECL_AND_RETURN( clef::make_expr_call(view_type(*this),arg0, args...));
template<typename Arg0, typename ...Args>
typename clef::result_of::make_expr_call<view_type,Arg0, Args...>::type
//typename clef::result_of::make_expr_call<gf_impl,Arg0, Args...>::type
typename clef::_result_of::make_expr_call<view_type,Arg0, Args...>::type
operator()(Arg0 arg0, Args... args) const {
return clef::make_expr_call(view_type(*this),arg0, args...);
}
/*
// on mesh component for composite meshes
// enable iif the first arg is a mesh_point_t for the first component of the mesh_t
template<typename Arg0, typename ... Args, bool MeshIsComposite = std::is_base_of<tag::composite, mesh_t>::value >
typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, r_type>::type
operator() (Arg0 const & arg0, Args const & ... args)
{ return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));}
typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, r_type>::type
operator() (Arg0 const & arg0, Args const & ... args)
{ return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));}
template<typename Arg0, typename ... Args, bool MeshIsComposite = std::is_base_of<tag::composite, mesh_t>::value >
typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, cr_type>::type
operator() (Arg0 const & arg0, Args const & ... args) const
{ return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));}
*/
typename std::enable_if< MeshIsComposite && std::is_base_of< tag::mesh_point, Arg0>::value, cr_type>::type
operator() (Arg0 const & arg0, Args const & ... args) const
{ return _data_proxy(_data, _mesh.mesh_pt_components_to_linear(arg0, args...));}
*/
//// [] and access to the grid point
typedef typename std::result_of<data_proxy_t(data_t &,size_t)>::type r_type;
@ -223,14 +228,29 @@ namespace triqs { namespace gfs {
cr_type operator[] (closest_pt_wrap<U...> const & p) const { return _data_proxy(_data, _mesh.index_to_linear( gfs_implementation::get_closest_point<Variable,Target,Opt>::invoke(this,p)));}
// Interaction with the CLEF library : calling the gf with any clef expression as argument build a new clef expression
/* template<typename Arg>
typename boost::lazy_enable_if< // enable the template if
clef::is_any_lazy<Arg>, // One of Args is a lazy expression
clef::_result_of::make_expr_subscript<view_type,Arg>
>::type // end of lazy_enable_if
operator[](Arg && arg) const { return clef::make_expr_subscript(view_type(*this),std::forward<Arg>(arg));}
*/
/*template<typename Arg>
//auto operator[](Arg && arg) const DECL_AND_RETURN(clef::make_expr_subscript((*this)(),std::forward<Arg>(arg)));
auto operator[](Arg && arg) const DECL_AND_RETURN(clef::make_expr_subscript(view_type(*this),std::forward<Arg>(arg)));
template<typename Arg>
typename boost::lazy_enable_if< // enable the template if
clef::is_any_lazy<Arg>, // One of Args is a lazy expression
clef::result_of::make_expr_subscript<view_type,Arg>
>::type // end of lazy_enable_if
//auto operator[](Arg && arg) DECL_AND_RETURN(clef::make_expr_subscript((*this)(),std::forward<Arg>(arg)));
auto operator[](Arg && arg) DECL_AND_RETURN(clef::make_expr_subscript(view_type(*this),std::forward<Arg>(arg)));
*/
template<typename Arg>
typename clef::_result_of::make_expr_subscript<view_type,Arg>::type
operator[](Arg && arg) const { return clef::make_expr_subscript(view_type(*this),std::forward<Arg>(arg));}
/// A direct access to the grid point
template<typename... Args>
r_type on_mesh (Args&&... args) { return _data_proxy(_data,_mesh.index_to_linear(mesh_index_t(std::forward<Args>(args)...)));}
@ -418,8 +438,8 @@ namespace triqs { namespace gfs {
return gf_view<Variable,scalar_valued,Opt>(g.mesh(), g.data()(range(), args... ), sg, g.symmetry());
}
// a scalar_valued gf can be viewed as a 1x1 matrix
template<typename Variable, typename Opt, bool V, typename... Args>
// a scalar_valued gf can be viewed as a 1x1 matrix
template<typename Variable, typename Opt, bool V, typename... Args>
gf_view<Variable,matrix_valued,Opt> reinterpret_scalar_valued_gf_as_matrix_valued (gf_impl<Variable,scalar_valued,Opt,V> const & g) {
typedef arrays::array_view<typename gfs_implementation::data_proxy<Variable,matrix_valued,Opt>::storage_t::value_type,3> a_t;
auto a = a_t {typename a_t::indexmap_type (arrays::mini_vector<size_t,3>(g.data().shape()[0],1,1)), g.data().storage()};

View File

@ -32,20 +32,11 @@
#if GCC_VERSION < 40801
//#warning "gcc compiler" GCC_VERSION
#define TRIQS_COMPILER_IS_OBSOLETE
#define TRIQS_COMPILER_OBSOLETE_GCC
// we still accept gcc 4.6 and 4.7, but only the 4.8.1 and higher is a compliant c++11
#endif
#endif
#ifdef __GXX_EXPERIMENTAL_CXX0X__
#define TRIQS_USE_STATIC_ASSERT
//#define USE_VARIADIC_TEMPLATES
#endif
#ifndef TRIQS_USE_STATIC_ASSERT
#include "boost/static_assert.hpp"
#define static_assert(X,MESS) BOOST_STATIC_ASSERT((X))
#endif
#endif

View File

@ -36,5 +36,9 @@
#define DECL_AND_RETURN(...) -> decltype(__VA_ARGS__) { return __VA_ARGS__;}
namespace triqs {
template<typename T> struct remove_cv_ref : std::remove_cv< typename std::remove_reference<T>::type> {};
};
#endif