diff --git a/triqs/clef/clef.c11.hpp b/triqs/clef/clef.c11.hpp new file mode 100644 index 00000000..f25a3667 --- /dev/null +++ b/triqs/clef/clef.c11.hpp @@ -0,0 +1,614 @@ +/******************************************************************************* + * + * TRIQS: a Toolbox for Research in Interacting Quantum Systems + * + * 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 + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * TRIQS. If not, see . + * + ******************************************************************************/ +#ifndef TRIQS_CLEF_CORE_H +#define TRIQS_CLEF_CORE_H +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TRIQS_CLEF_MAXNARGS 8 + +namespace triqs { namespace clef { + using ull_t = unsigned long long; + namespace tags { struct function_class{}; struct function{}; struct subscript{}; struct terminal{}; struct if_else{}; struct unary_op{}; struct binary_op{}; } + + // Compute the type to put in the expression tree. + // If T is a lvalue reference, pack it into a reference_wrapper, unless force_copy_in_expr::value == true + // If T is an rvalue reference, we store it as the type (using move semantics). + template struct force_copy_in_expr : std::false_type{}; + template struct force_copy_in_expr : force_copy_in_expr{}; + + template< class T > struct expr_storage_impl {typedef T type;}; + template< class T > struct expr_storage_impl : std::conditional::value, typename std::remove_const::type ,std::reference_wrapper>{}; + template< class T > struct expr_storage_impl {typedef T type;}; + template< class T > struct expr_storage_impl {typedef T type;}; + template< class T > struct expr_storage_impl {typedef T type;}; + + template using expr_storage_t = typename expr_storage_impl::type; // helper type + + /* --------------------------------------------------------------------------------------------------- + * Placeholder and corresponding traits + * --------------------------------------------------------------------------------------------------- */ + template struct pair; // forward + + // a placeholder is an empty struct, labelled by an int. + template struct placeholder { + static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]"); + static constexpr int index = N; + template pair operator = (RHS && rhs) { return {std::forward(rhs)};} + }; + + // placeholder will always be copied (they are empty anyway). + template struct force_copy_in_expr> : std::true_type {}; + + // represent a couple (placeholder, value). + template struct pair { + U rhs; + static constexpr int p = N; + using value_type = typename remove_cv_ref::type; + }; + + // ph_set is a trait that given a pack of type, returns the set of placeholders they contain + // it returns a int in binary coding : bit N in the int is 1 iif at least one T is lazy and contains placeholder + template struct ph_set; + template struct ph_set{static constexpr ull_t value= ph_set::value| ph_set::value;}; + template struct ph_set {static constexpr ull_t value= 0;}; + template struct ph_set> {static constexpr ull_t value= 1ull< struct ph_set > : ph_set>{}; + + // in_any_lazy : trait to detect if any of Args is a lazy expression + template struct is_any_lazy : std::false_type {}; + template struct is_any_lazy > : std::true_type {}; + template struct is_any_lazy< T > : std::false_type {}; + template struct is_any_lazy< T&& > : is_any_lazy {}; + template struct is_any_lazy< T& > : is_any_lazy {}; + template struct is_any_lazy< T const > : is_any_lazy {}; + template struct is_any_lazy : + std::integral_constant::value || is_any_lazy::value> {}; + + template + constexpr bool ClefExpression() { return is_any_lazy::value;} + + template struct is_clef_expression : is_any_lazy{}; + + /* --------------------------------------------------------------------------------------------------- + * Node of the expression tree + * --------------------------------------------------------------------------------------------------- */ + template struct expr { + // T can be U, U & (a reference or a value). + using childs_t = std::tuple; + childs_t childs; + expr(expr const & x) = default; + expr(expr && x) noexcept : childs(std::move(x.childs)) {} + // a constructor with the Tag make it unambiguous with other constructors... + template expr(Tag, Args&&...args) : childs(std::forward(args)...) {} + // [] returns a new lazy expression, with one more layer + template + expr > operator[](Args && args) const + { return {tags::subscript(), *this,std::forward(args)};} + // () also ... + template< typename... Args > + expr...> operator()(Args && ... args) const + { return {tags::function(), *this,std::forward(args)...};} + // assignement is in general deleted + expr & operator= (expr const &) = delete; // no ordinary assignment + expr & operator= (expr &&) = default; // move assign ok + // however, this is ok in the case f(i,j) = expr, where f is a clef::function + template + ENABLE_IF(std::is_base_of::type>) + operator= (RHS const & rhs) { *this << rhs;} + template + DISABLE_IF(std::is_base_of::type>) + operator= (RHS const & rhs) = delete; + }; + // set some traits + template struct ph_set< expr > : ph_set {}; + template struct is_any_lazy< expr >: std::true_type {}; + // if we want that subexpression are copied ? + template struct force_copy_in_expr< expr > : std::true_type{}; + + template using expr_node_t = expr...>; + + /* --------------------------------------------------------------------------------------------------- + * The basic operations put in a template.... + * --------------------------------------------------------------------------------------------------- */ + template struct operation; + + // a little function to clean the reference_wrapper + template U _cl(U && x) { return std::forward(x);} + template auto _cl(std::reference_wrapper x) DECL_AND_RETURN(x.get()); + + /// Terminal + template<> struct operation { template L operator()(L&& l) const { return std::forward(l);} }; + + /// Function call + template<> struct operation { + template + auto operator()(F&& f, Args&&... args) const DECL_AND_RETURN(_cl(std::forward(f))(_cl(std::forward(args))...)); + }; + + /// [ ] Call + template<> struct operation { + template + auto operator()(F&& f, Args&& args) const DECL_AND_RETURN(_cl(std::forward(f))[_cl(std::forward(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 \ + std14::enable_if_t::value, expr, expr_storage_t>> operator OP(L&& l, R&& r) { \ + return {tags::TAG(), std::forward(l), std::forward(r)}; \ + } \ + template <> struct operation { \ + template \ + auto operator()(L&& l, R&& r) const DECL_AND_RETURN(_cl(std::forward(l)) OP _cl(std::forward(r))); \ + }; + + TRIQS_CLEF_OPERATION(plus, +); + TRIQS_CLEF_OPERATION(minus, -); + TRIQS_CLEF_OPERATION(multiplies, *); + TRIQS_CLEF_OPERATION(divides, /); + TRIQS_CLEF_OPERATION(greater, >); + TRIQS_CLEF_OPERATION(less, <); + TRIQS_CLEF_OPERATION(leq, <=); + TRIQS_CLEF_OPERATION(geq, >=); + TRIQS_CLEF_OPERATION(eq, ==); +#undef TRIQS_CLEF_OPERATION + + // all unary operators.... +#define TRIQS_CLEF_OPERATION(TAG, OP) \ + namespace tags { \ + struct TAG : unary_op { \ + static const char* name() { return BOOST_PP_STRINGIZE(OP); } \ + }; \ + } \ + template \ + std14::enable_if_t::value, expr>> operator OP(L&& l) { \ + return {tags::TAG(), std::forward(l)}; \ + } \ + template <> struct operation { \ + template auto operator()(L&& l) const DECL_AND_RETURN(OP _cl(std::forward(l))); \ + }; + + TRIQS_CLEF_OPERATION(negate, -); + TRIQS_CLEF_OPERATION(loginot, !); +#undef TRIQS_CLEF_OPERATION + + /// the only ternary node : expression if + template<> struct operation { + // A and B MUST be the same + template A operator()(C const & c, A const & a, B const & b) const {return _cl(c) ? _cl(a): _cl(b);} + //template auto operator()(C const & c, A const & a, B const & b) const DECL_AND_RETURN (_cl(c) ? _cl(a): _cl(b)); + }; + // operator is : if_else( Condition, A, B) + template + expr,expr_storage_t,expr_storage_t> + if_else(C && c, A && a, B && b) { return {tags::if_else(),std::forward(c),std::forward(a),std::forward(b)};} + + /* --------------------------------------------------------------------------------------------------- + * Evaluation of the expression tree. + * --------------------------------------------------------------------------------------------------- */ + + constexpr bool __or() { return false;} + template constexpr bool __or(bool b, B... bs) { return b || __or(bs...); } + + // Generic case : do nothing (for the leaf of the tree including placeholder) + template struct evaluator { + static constexpr bool is_lazy = is_any_lazy::value; + T const & operator()(T const& k, Pairs const&... pairs) const { return k; } + }; + + // The general eval function for expressions : declaration only + template + auto eval (T const & ex, Pairs const &... pairs) ->decltype( evaluator()(ex, pairs...)); + + // placeholder + template struct evaluator, pair, Pairs...> { + using eval_t = evaluator, Pairs...>; + static constexpr bool is_lazy = eval_t::is_lazy; + auto operator()(placeholder, pair const&, Pairs const&... pairs) const + DECL_AND_RETURN(eval_t()(placeholder(), pairs...)); + }; + + template struct evaluator, pair, Pairs...> { + static constexpr bool is_lazy = false; + T operator()(placeholder, pair const& p, Pairs const&...) const { return p.rhs; } + }; + + // any object hold by reference wrapper is redirected to the evaluator of the object + template struct evaluator, Contexts...> { + //using ev_t = evaluator; + static constexpr bool is_lazy = false;//ev_t::is_lazy; + auto operator()(std::reference_wrapper const& x, Contexts const&... contexts) const DECL_AND_RETURN(eval(x.get(), contexts...)); + }; + + // dispatching the evaluation : if lazy, we make a new clef expression, if not we call the operation + template struct op_dispatch; + + template struct op_dispatch { + template expr...> operator()(Args&&... args) const { + return {Tag(), std::forward(args)...}; + } + }; + + template struct op_dispatch { + template + auto operator()(Args&&... args) const DECL_AND_RETURN(operation()(std::forward(args)...)); + }; + + // general expr node + +#ifdef TRIQS_USE_C14_DRAFT__ + template struct evaluator, Pairs...> { + + static constexpr bool is_lazy = __or(evaluator::is_lazy...); + + auto operator()(expr const& ex, Pairs const&... pairs) const { + auto eval_in_context = [&pairs...](auto const& _child) { return eval(_child, pairs...); }; + return tuple::apply_compose(op_dispatch{}, eval_in_context, ex.childs); + } + }; +#else + // WORKAROUND FOR C++11 compilers + template struct evaluator_node_gal; + + template struct evaluator_node_gal<1, expr, Pairs...> { + static constexpr bool is_lazy = __or(evaluator::is_lazy...); + auto operator()(expr const& ex, Pairs const&... pairs) const + DECL_AND_RETURN(op_dispatch {}(eval(std::get<0>(ex.childs), pairs...))); + }; + + template struct evaluator_node_gal<2, expr, Pairs...> { + static constexpr bool is_lazy = __or(evaluator::is_lazy...); + auto operator()(expr const& ex, Pairs const&... pairs) const + DECL_AND_RETURN(op_dispatch {}(eval(std::get<0>(ex.childs), pairs...), eval(std::get<1>(ex.childs), pairs...))); + }; + +// the general case for more than 2 nodes. I put 1 and 2 nodes apart, just because it is the most frequent +// and macros yield more obscure error messages in case of a pb ... +#define AUX(z, p, unused) eval(std::get

(ex.childs), pairs...) +#define IMPL(z, NN, unused) \ + template struct evaluator_node_gal, Pairs...> { \ + static constexpr bool is_lazy = __or(evaluator::is_lazy...); \ + auto operator()(expr const& ex, Pairs const&... pairs) const \ + DECL_AND_RETURN(op_dispatch {}(BOOST_PP_ENUM(NN, AUX, nil))); \ + }; + BOOST_PP_REPEAT_FROM_TO(3,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil); +#undef AUX +#undef IMPL + + template + struct evaluator, Pairs...> : evaluator_node_gal, Pairs...>{}; +#endif + + // The general eval function for expressions + template + decltype(auto) eval(T const& ex, Pairs const&... pairs) { return evaluator()(ex, pairs...);} + + /* --------------------------------------------------------------------------------------------------- + * Apply a function object to all the leaves of the expression tree + * --------------------------------------------------------------------------------------------------- */ + + template struct apply_on_each_leaf_impl { + F f; + template std::c14::enable_if_t::value> operator()(T const& ex) { + tuple::for_each(ex.childs, *this); + } + template std::c14::enable_if_t::value> operator()(T const& x) { f(x); } + template std::c14::enable_if_t::value> operator()(std::reference_wrapper const& x) { + f(x.get()); + } + }; + + template void apply_on_each_leaf(F&& f, Expr const& ex) { + auto impl = apply_on_each_leaf_impl{std::forward(f)}; + impl(ex); + } + + /* --------------------------------------------------------------------------------------------------- + * make_function : transform an expression to a function + * --------------------------------------------------------------------------------------------------- */ + + template< typename Expr, int... Is> struct make_fun_impl { + Expr ex; // keep a copy of the expression + make_fun_impl(Expr const & ex_) : ex(ex_) {} + + template + decltype(auto) operator()(Args &&... args) const { return evaluator...>() ( ex, pair{std::forward(args)}...);} + }; + + // values of the ph, excluding the Is ... + template struct ph_filter; + template struct ph_filter { static constexpr ull_t value = ph_filter::value & (~ (1ull< struct ph_filter { static constexpr ull_t value = x; }; + + template< typename Expr, int... Is> struct ph_set > { static constexpr ull_t value = ph_filter ::value, Is...>::value;}; + template< typename Expr, int... Is> struct is_any_lazy > : std::integral_constant>::value !=0>{}; + template< typename Expr, int... Is> struct force_copy_in_expr > : std::true_type{}; + + template< typename Expr, typename ... Phs> + make_fun_impl::type,Phs::index...> + make_function(Expr && ex, Phs...) { return {ex}; } + + namespace result_of { + template< typename Expr, typename ... Phs> struct make_function { + using type = make_fun_impl::type, Phs::index...>; + }; + } + + template< typename Expr, int... Is,typename... Pairs> struct evaluator, Pairs...> { + using e_t = evaluator; + //using is_lazy = std::integral_constant>::value != ph_set::value>; + static constexpr bool is_lazy = (ph_set>::value != ph_set::value); + decltype(auto) operator()(make_fun_impl const & f, Pairs const & ... pairs) const { return make_function( e_t()(f.ex, pairs...),placeholder()...);} + }; + + template struct ph_list {}; + template ph_list var( placeholder ...) { return {};} + + template + decltype(auto) operator >> (ph_list, Expr const & ex) { return make_function(ex, placeholder()...);} + + /* -------------------------------------------------------------------------------------------------- + * make_function + * x_ >> expression is the same as make_function(expression,x) + * --------------------------------------------------------------------------------------------------- */ + + template + make_fun_impl operator >> (placeholder p, Expr&& ex) { return {ex}; } + + /* --------------------------------------------------------------------------------------------------- + * Auto assign for () + * --------------------------------------------------------------------------------------------------- */ + + // by default it is deleted = not implemented : every class has to define it... + template void triqs_clef_auto_assign (T,F) = delete; + + // remove the ref_wrapper, terminal ... + template void triqs_clef_auto_assign(std::reference_wrapper R, F&& f) { + triqs_clef_auto_assign(R.get(), std::forward(f)); + } + template void triqs_clef_auto_assign(expr const& t, F&& f) { + triqs_clef_auto_assign(std::get<0>(t.childs), std::forward(f)); + } + + // auto assign of an expr ? (for chain calls) : just reuse the same operator + template + void triqs_clef_auto_assign(expr&& ex, RHS const& rhs) { + ex << rhs; + } + + template + void triqs_clef_auto_assign(expr const& ex, RHS const& rhs) { + ex << rhs; + } + + // The case A(x_,y_) = RHS : we form the function (make_function) and call auto_assign (by ADL) + template void operator<<(expr...>&& ex, RHS&& rhs) { + triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); + } + template + void operator<<(expr...> const& ex, RHS&& rhs) { + triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); + } + template void operator<<(expr...>& ex, RHS&& rhs) { + triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); + } + + // any other case e.g. f(x_+y_) = RHS etc .... which makes no sense : compiler will stop + template void operator<<(expr&& ex, RHS&& rhs) = delete; + template void operator<<(expr& ex, RHS&& rhs) = delete; + template void operator<<(expr const& ex, RHS&& rhs) = delete; + + /* --------------------------------------------------------------------------------------------------- + * Auto assign for [] + * --------------------------------------------------------------------------------------------------- */ + + // by default it is deleted = not implemented : every class has to define it... + template void triqs_clef_auto_assign_subscript (T,F) = delete; + + // remove the ref_wrapper, terminal ... + template void triqs_clef_auto_assign_subscript (std::reference_wrapper R ,F && f) + { triqs_clef_auto_assign_subscript(R.get(),std::forward(f));} + template void triqs_clef_auto_assign_subscript (expr const & t,F && f) + { triqs_clef_auto_assign_subscript(std::get<0>(t.childs),std::forward(f));} + + // auto assign of an expr ? (for chain calls) : just reuse the same operator + template + void triqs_clef_auto_assign_subscript (expr && ex, RHS const & rhs) { ex << rhs;} + + template + void triqs_clef_auto_assign_subscript (expr const & ex, RHS const & rhs) { ex << rhs;} + + // Same thing for the [ ] + template + void operator<<(expr...> const & ex, RHS && rhs) { + triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); + } + template + void operator<<(expr...> && ex, RHS && rhs) { + triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); + } + + template void operator<<(expr&& ex, RHS&& rhs) = delete; + template void operator<<(expr& ex, RHS&& rhs) = delete; + template void operator<<(expr const& ex, RHS&& rhs) = delete; + + /* -------------------------------------------------------------------------------------------------- + * Create a terminal node of an object. the from clone version force copying the object + * --------------------------------------------------------------------------------------------------- */ + + // make a node with the ref, unless it is an rvalue (which is moved). + template expr > + make_expr(T && x){ return {tags::terminal(), std::forward(x)};} + + // make a node from a copy of the object + template expr::type > + make_expr_from_clone(T && x){ return {tags::terminal(), std::forward(x)};} + + /* -------------------------------------------------------------------------------------------------- + * Create a call node of an object + * The object can be kept as a : a ref, a copy, a view + * --------------------------------------------------------------------------------------------------- */ + + template struct arity { static constexpr int value =-1;}; + + namespace _result_of { + template< typename Obj, typename... Args > struct make_expr_call : + std::enable_if< is_any_lazy::value, expr, expr_storage_t ...> > { + static_assert (((arity::value==-1) || (arity::value == sizeof...(Args))), "Object called with a wrong number of arguments"); + }; + } + template< typename Obj, typename... Args > + typename _result_of::make_expr_call::type + make_expr_call(Obj&& obj, Args &&... args) { return {tags::function(),std::forward(obj), std::forward(args)...};} + + /* -------------------------------------------------------------------------------------------------- + * Create a [] call (subscript) node of an object + * The object can be kept as a : a ref, a copy, a view + * --------------------------------------------------------------------------------------------------- */ + + namespace _result_of { + template< typename Obj, typename Arg> struct make_expr_subscript : + std::enable_if< is_any_lazy::value, expr, expr_storage_t> > {}; + } + template< typename Obj, typename Arg> + typename _result_of::make_expr_subscript::type + make_expr_subscript(Obj&& obj, Arg && arg) { return {tags::subscript(),std::forward(obj), std::forward(arg)};} + + /* -------------------------------------------------------------------------------------------------- + * function class : stores any expression polymorphically + * f(x_,y_ ) = an expression associates this expression dynamically to f, which + * can then be used as a std::function of the same signature... + * --------------------------------------------------------------------------------------------------- */ + template class function; + + template class function : tags::function_class { + using std_function_type = std::function; + mutable std::shared_ptr _exp; // CLEAN THIS MUTABLE ? + mutable std::shared_ptr < std_function_type > _fnt_ptr; + public: + function():_fnt_ptr{std::make_shared ()}{} + + template + explicit function(Expr const& _e, X... x) + : _exp(std::make_shared(_e)), _fnt_ptr(new std_function_type(make_function(_e, x...))) {} + + ReturnType operator()(T const &... t) const { return (*_fnt_ptr)(t...);} + + template< typename... Args> + auto operator()( Args&&... args ) const DECL_AND_RETURN(make_expr_call (*this,std::forward(args)...)); + + template friend void triqs_clef_auto_assign (function const & x, RHS rhs) { + * (x._fnt_ptr) = std_function_type (rhs); + x._exp = std::make_shared::type> (rhs.ex); + } + + }; + template struct force_copy_in_expr > : std::true_type{}; + + /* -------------------------------------------------------------------------------------------------- + * The macro to make any function lazy + * TRIQS_CLEF_MAKE_FNT_LAZY (Arity,FunctionName ) : creates a new function in the triqs::lazy namespace + * taking expressions (at least one argument has to be an expression) + * The lookup happens by ADL, so IT MUST BE USED IN THE triqs::lazy namespace + * --------------------------------------------------------------------------------------------------- */ +#define TRIQS_CLEF_MAKE_FNT_LAZY(name) \ + struct name##_lazy_impl { \ + template decltype(auto) operator()(A&&... a) const { return name(std::forward(a)...);} \ + }; \ + template auto name(A&&... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(), std::forward(a)...)); + +#define TRIQS_CLEF_EXTEND_FNT_LAZY(FUN, TRAIT) \ + template \ + std::c14::enable_if_t::value, clef::expr_node_t> FUN(A&& a) { \ + return {clef::tags::function{}, clef::FUN##_lazy_impl{}, std::forward(a)}; \ + } + +#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY, name) \ + struct __clef_lazy_method_impl_##TY##_##name { \ + template decltype(auto) operator()(X&& x, A&&... a) const { return x.name(std::forward(a)...);} \ + friend std::ostream& operator<<(std::ostream& out, __clef_lazy_method_impl_##TY##_##name const& x) { \ + return out << "apply_method:"<< BOOST_PP_STRINGIZE(name); \ + } \ + }; \ + template \ + auto name(A&&... a) DECL_AND_RETURN(make_expr_call(__clef_lazy_method_impl_##TY##_##name{}, *this, std::forward(a)...)); + +#define TRIQS_CLEF_IMPLEMENT_LAZY_CALL(...) \ + template \ + auto operator()(Args&&... args) const& DECL_AND_RETURN(make_expr_call(*this, std::forward(args)...)); \ + \ + template \ + auto operator()(Args&&... args) & DECL_AND_RETURN(make_expr_call(*this, std::forward(args)...)); \ + \ + template \ + auto operator()(Args&&... args) && DECL_AND_RETURN(make_expr_call(std::move(*this), std::forward(args)...)); + +/* -------------------------------------------------------------------------------------------------- + * sum of expressions + * --------------------------------------------------------------------------------------------------- */ + + // sum a function f on a domain D, using a simple foreach + template + auto sum_f_domain_impl(F const& f, D const& d) + -> std::c14::enable_if_t::value, decltype(f(*(d.begin())))> { + auto res = decltype(f(*(d.begin()))) {}; + using p_t = typename std::decay::type; + foreach(d, [&res, &f](p_t const& x) { res = res + f(x); }); + return res; + } + + TRIQS_CLEF_MAKE_FNT_LAZY(sum_f_domain_impl); + + // sum( expression, i = domain) + template decltype(auto) sum(Expr const& f, clef::pair const& d) { + return sum_f_domain_impl(make_function(f, clef::placeholder()), d.rhs); + } + + // two or more indices : sum recursively + template + auto sum(Expr const& f, clef::pair const& d0, clef::pair const& d1, clef::pair const&... d) { + return sum(sum(f, d0), d1, d...); + } +}} // namespace triqs::clef diff --git a/triqs/clef/clef.hpp b/triqs/clef/clef.hpp index f25a3667..f8d87f7d 100644 --- a/triqs/clef/clef.hpp +++ b/triqs/clef/clef.hpp @@ -18,597 +18,12 @@ * TRIQS. If not, see . * ******************************************************************************/ -#ifndef TRIQS_CLEF_CORE_H -#define TRIQS_CLEF_CORE_H -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TRIQS_CLEF_MAXNARGS 8 - -namespace triqs { namespace clef { - using ull_t = unsigned long long; - namespace tags { struct function_class{}; struct function{}; struct subscript{}; struct terminal{}; struct if_else{}; struct unary_op{}; struct binary_op{}; } - - // Compute the type to put in the expression tree. - // If T is a lvalue reference, pack it into a reference_wrapper, unless force_copy_in_expr::value == true - // If T is an rvalue reference, we store it as the type (using move semantics). - template struct force_copy_in_expr : std::false_type{}; - template struct force_copy_in_expr : force_copy_in_expr{}; - - template< class T > struct expr_storage_impl {typedef T type;}; - template< class T > struct expr_storage_impl : std::conditional::value, typename std::remove_const::type ,std::reference_wrapper>{}; - template< class T > struct expr_storage_impl {typedef T type;}; - template< class T > struct expr_storage_impl {typedef T type;}; - template< class T > struct expr_storage_impl {typedef T type;}; - - template using expr_storage_t = typename expr_storage_impl::type; // helper type - - /* --------------------------------------------------------------------------------------------------- - * Placeholder and corresponding traits - * --------------------------------------------------------------------------------------------------- */ - template struct pair; // forward - - // a placeholder is an empty struct, labelled by an int. - template struct placeholder { - static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]"); - static constexpr int index = N; - template pair operator = (RHS && rhs) { return {std::forward(rhs)};} - }; - - // placeholder will always be copied (they are empty anyway). - template struct force_copy_in_expr> : std::true_type {}; - - // represent a couple (placeholder, value). - template struct pair { - U rhs; - static constexpr int p = N; - using value_type = typename remove_cv_ref::type; - }; - - // ph_set is a trait that given a pack of type, returns the set of placeholders they contain - // it returns a int in binary coding : bit N in the int is 1 iif at least one T is lazy and contains placeholder - template struct ph_set; - template struct ph_set{static constexpr ull_t value= ph_set::value| ph_set::value;}; - template struct ph_set {static constexpr ull_t value= 0;}; - template struct ph_set> {static constexpr ull_t value= 1ull< struct ph_set > : ph_set>{}; - - // in_any_lazy : trait to detect if any of Args is a lazy expression - template struct is_any_lazy : std::false_type {}; - template struct is_any_lazy > : std::true_type {}; - template struct is_any_lazy< T > : std::false_type {}; - template struct is_any_lazy< T&& > : is_any_lazy {}; - template struct is_any_lazy< T& > : is_any_lazy {}; - template struct is_any_lazy< T const > : is_any_lazy {}; - template struct is_any_lazy : - std::integral_constant::value || is_any_lazy::value> {}; - - template - constexpr bool ClefExpression() { return is_any_lazy::value;} - - template struct is_clef_expression : is_any_lazy{}; - - /* --------------------------------------------------------------------------------------------------- - * Node of the expression tree - * --------------------------------------------------------------------------------------------------- */ - template struct expr { - // T can be U, U & (a reference or a value). - using childs_t = std::tuple; - childs_t childs; - expr(expr const & x) = default; - expr(expr && x) noexcept : childs(std::move(x.childs)) {} - // a constructor with the Tag make it unambiguous with other constructors... - template expr(Tag, Args&&...args) : childs(std::forward(args)...) {} - // [] returns a new lazy expression, with one more layer - template - expr > operator[](Args && args) const - { return {tags::subscript(), *this,std::forward(args)};} - // () also ... - template< typename... Args > - expr...> operator()(Args && ... args) const - { return {tags::function(), *this,std::forward(args)...};} - // assignement is in general deleted - expr & operator= (expr const &) = delete; // no ordinary assignment - expr & operator= (expr &&) = default; // move assign ok - // however, this is ok in the case f(i,j) = expr, where f is a clef::function - template - ENABLE_IF(std::is_base_of::type>) - operator= (RHS const & rhs) { *this << rhs;} - template - DISABLE_IF(std::is_base_of::type>) - operator= (RHS const & rhs) = delete; - }; - // set some traits - template struct ph_set< expr > : ph_set {}; - template struct is_any_lazy< expr >: std::true_type {}; - // if we want that subexpression are copied ? - template struct force_copy_in_expr< expr > : std::true_type{}; - - template using expr_node_t = expr...>; - - /* --------------------------------------------------------------------------------------------------- - * The basic operations put in a template.... - * --------------------------------------------------------------------------------------------------- */ - template struct operation; - - // a little function to clean the reference_wrapper - template U _cl(U && x) { return std::forward(x);} - template auto _cl(std::reference_wrapper x) DECL_AND_RETURN(x.get()); - - /// Terminal - template<> struct operation { template L operator()(L&& l) const { return std::forward(l);} }; - - /// Function call - template<> struct operation { - template - auto operator()(F&& f, Args&&... args) const DECL_AND_RETURN(_cl(std::forward(f))(_cl(std::forward(args))...)); - }; - - /// [ ] Call - template<> struct operation { - template - auto operator()(F&& f, Args&& args) const DECL_AND_RETURN(_cl(std::forward(f))[_cl(std::forward(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 \ - std14::enable_if_t::value, expr, expr_storage_t>> operator OP(L&& l, R&& r) { \ - return {tags::TAG(), std::forward(l), std::forward(r)}; \ - } \ - template <> struct operation { \ - template \ - auto operator()(L&& l, R&& r) const DECL_AND_RETURN(_cl(std::forward(l)) OP _cl(std::forward(r))); \ - }; - - TRIQS_CLEF_OPERATION(plus, +); - TRIQS_CLEF_OPERATION(minus, -); - TRIQS_CLEF_OPERATION(multiplies, *); - TRIQS_CLEF_OPERATION(divides, /); - TRIQS_CLEF_OPERATION(greater, >); - TRIQS_CLEF_OPERATION(less, <); - TRIQS_CLEF_OPERATION(leq, <=); - TRIQS_CLEF_OPERATION(geq, >=); - TRIQS_CLEF_OPERATION(eq, ==); -#undef TRIQS_CLEF_OPERATION - - // all unary operators.... -#define TRIQS_CLEF_OPERATION(TAG, OP) \ - namespace tags { \ - struct TAG : unary_op { \ - static const char* name() { return BOOST_PP_STRINGIZE(OP); } \ - }; \ - } \ - template \ - std14::enable_if_t::value, expr>> operator OP(L&& l) { \ - return {tags::TAG(), std::forward(l)}; \ - } \ - template <> struct operation { \ - template auto operator()(L&& l) const DECL_AND_RETURN(OP _cl(std::forward(l))); \ - }; - - TRIQS_CLEF_OPERATION(negate, -); - TRIQS_CLEF_OPERATION(loginot, !); -#undef TRIQS_CLEF_OPERATION - - /// the only ternary node : expression if - template<> struct operation { - // A and B MUST be the same - template A operator()(C const & c, A const & a, B const & b) const {return _cl(c) ? _cl(a): _cl(b);} - //template auto operator()(C const & c, A const & a, B const & b) const DECL_AND_RETURN (_cl(c) ? _cl(a): _cl(b)); - }; - // operator is : if_else( Condition, A, B) - template - expr,expr_storage_t,expr_storage_t> - if_else(C && c, A && a, B && b) { return {tags::if_else(),std::forward(c),std::forward(a),std::forward(b)};} - - /* --------------------------------------------------------------------------------------------------- - * Evaluation of the expression tree. - * --------------------------------------------------------------------------------------------------- */ - - constexpr bool __or() { return false;} - template constexpr bool __or(bool b, B... bs) { return b || __or(bs...); } - - // Generic case : do nothing (for the leaf of the tree including placeholder) - template struct evaluator { - static constexpr bool is_lazy = is_any_lazy::value; - T const & operator()(T const& k, Pairs const&... pairs) const { return k; } - }; - - // The general eval function for expressions : declaration only - template - auto eval (T const & ex, Pairs const &... pairs) ->decltype( evaluator()(ex, pairs...)); - - // placeholder - template struct evaluator, pair, Pairs...> { - using eval_t = evaluator, Pairs...>; - static constexpr bool is_lazy = eval_t::is_lazy; - auto operator()(placeholder, pair const&, Pairs const&... pairs) const - DECL_AND_RETURN(eval_t()(placeholder(), pairs...)); - }; - - template struct evaluator, pair, Pairs...> { - static constexpr bool is_lazy = false; - T operator()(placeholder, pair const& p, Pairs const&...) const { return p.rhs; } - }; - - // any object hold by reference wrapper is redirected to the evaluator of the object - template struct evaluator, Contexts...> { - //using ev_t = evaluator; - static constexpr bool is_lazy = false;//ev_t::is_lazy; - auto operator()(std::reference_wrapper const& x, Contexts const&... contexts) const DECL_AND_RETURN(eval(x.get(), contexts...)); - }; - - // dispatching the evaluation : if lazy, we make a new clef expression, if not we call the operation - template struct op_dispatch; - - template struct op_dispatch { - template expr...> operator()(Args&&... args) const { - return {Tag(), std::forward(args)...}; - } - }; - - template struct op_dispatch { - template - auto operator()(Args&&... args) const DECL_AND_RETURN(operation()(std::forward(args)...)); - }; - - // general expr node - -#ifdef TRIQS_USE_C14_DRAFT__ - template struct evaluator, Pairs...> { - - static constexpr bool is_lazy = __or(evaluator::is_lazy...); - - auto operator()(expr const& ex, Pairs const&... pairs) const { - auto eval_in_context = [&pairs...](auto const& _child) { return eval(_child, pairs...); }; - return tuple::apply_compose(op_dispatch{}, eval_in_context, ex.childs); - } - }; +#pragma once +#if defined(__cpp_generic_lambdas) && defined (__cpp_decltype_auto) && defined(__cpp_return_type_deduction) +// simplest code, in c++14 +#include "./clef.c14.hpp" #else - // WORKAROUND FOR C++11 compilers - template struct evaluator_node_gal; - - template struct evaluator_node_gal<1, expr, Pairs...> { - static constexpr bool is_lazy = __or(evaluator::is_lazy...); - auto operator()(expr const& ex, Pairs const&... pairs) const - DECL_AND_RETURN(op_dispatch {}(eval(std::get<0>(ex.childs), pairs...))); - }; - - template struct evaluator_node_gal<2, expr, Pairs...> { - static constexpr bool is_lazy = __or(evaluator::is_lazy...); - auto operator()(expr const& ex, Pairs const&... pairs) const - DECL_AND_RETURN(op_dispatch {}(eval(std::get<0>(ex.childs), pairs...), eval(std::get<1>(ex.childs), pairs...))); - }; - -// the general case for more than 2 nodes. I put 1 and 2 nodes apart, just because it is the most frequent -// and macros yield more obscure error messages in case of a pb ... -#define AUX(z, p, unused) eval(std::get

(ex.childs), pairs...) -#define IMPL(z, NN, unused) \ - template struct evaluator_node_gal, Pairs...> { \ - static constexpr bool is_lazy = __or(evaluator::is_lazy...); \ - auto operator()(expr const& ex, Pairs const&... pairs) const \ - DECL_AND_RETURN(op_dispatch {}(BOOST_PP_ENUM(NN, AUX, nil))); \ - }; - BOOST_PP_REPEAT_FROM_TO(3,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil); -#undef AUX -#undef IMPL - - template - struct evaluator, Pairs...> : evaluator_node_gal, Pairs...>{}; +// workaround for C++11 +#include "./clef.c11.hpp" #endif - // The general eval function for expressions - template - auto eval(T const& ex, Pairs const&... pairs) DECL_AND_RETURN(evaluator()(ex, pairs...)); - - /* --------------------------------------------------------------------------------------------------- - * Apply a function object to all the leaves of the expression tree - * --------------------------------------------------------------------------------------------------- */ - - template struct apply_on_each_leaf_impl { - F f; - template std::c14::enable_if_t::value> operator()(T const& ex) { - tuple::for_each(ex.childs, *this); - } - template std::c14::enable_if_t::value> operator()(T const& x) { f(x); } - template std::c14::enable_if_t::value> operator()(std::reference_wrapper const& x) { - f(x.get()); - } - }; - - template void apply_on_each_leaf(F&& f, Expr const& ex) { - auto impl = apply_on_each_leaf_impl{std::forward(f)}; - impl(ex); - } - - /* --------------------------------------------------------------------------------------------------- - * make_function : transform an expression to a function - * --------------------------------------------------------------------------------------------------- */ - - template< typename Expr, int... Is> struct make_fun_impl { - Expr ex; // keep a copy of the expression - make_fun_impl(Expr const & ex_) : ex(ex_) {} - - template - auto operator()(Args &&... args) const - DECL_AND_RETURN( evaluator...>() ( ex, pair{std::forward(args)}...)); - }; - - // values of the ph, excluding the Is ... - template struct ph_filter; - template struct ph_filter { static constexpr ull_t value = ph_filter::value & (~ (1ull< struct ph_filter { static constexpr ull_t value = x; }; - - template< typename Expr, int... Is> struct ph_set > { static constexpr ull_t value = ph_filter ::value, Is...>::value;}; - template< typename Expr, int... Is> struct is_any_lazy > : std::integral_constant>::value !=0>{}; - template< typename Expr, int... Is> struct force_copy_in_expr > : std::true_type{}; - - template< typename Expr, typename ... Phs> - make_fun_impl::type,Phs::index...> - make_function(Expr && ex, Phs...) { return {ex}; } - - namespace result_of { - template< typename Expr, typename ... Phs> struct make_function { - using type = make_fun_impl::type, Phs::index...>; - }; - } - - template< typename Expr, int... Is,typename... Pairs> struct evaluator, Pairs...> { - using e_t = evaluator; - //using is_lazy = std::integral_constant>::value != ph_set::value>; - static constexpr bool is_lazy = (ph_set>::value != ph_set::value); - auto operator()(make_fun_impl const & f, Pairs const & ... pairs) const DECL_AND_RETURN( make_function( e_t()(f.ex, pairs...),placeholder()...)); - }; - - template struct ph_list {}; - template ph_list var( placeholder ...) { return {};} - - template - auto operator >> (ph_list, Expr const & ex) DECL_AND_RETURN( make_function(ex, placeholder()...)); - - /* -------------------------------------------------------------------------------------------------- - * make_function - * x_ >> expression is the same as make_function(expression,x) - * --------------------------------------------------------------------------------------------------- */ - - template - make_fun_impl operator >> (placeholder p, Expr&& ex) { return {ex}; } - - /* --------------------------------------------------------------------------------------------------- - * Auto assign for () - * --------------------------------------------------------------------------------------------------- */ - - // by default it is deleted = not implemented : every class has to define it... - template void triqs_clef_auto_assign (T,F) = delete; - - // remove the ref_wrapper, terminal ... - template void triqs_clef_auto_assign (std::reference_wrapper R ,F && f) { triqs_clef_auto_assign(R.get(),std::forward(f));} - template void triqs_clef_auto_assign (expr const & t,F && f) { triqs_clef_auto_assign(std::get<0>(t.childs),std::forward(f));} - - // auto assign of an expr ? (for chain calls) : just reuse the same operator - template - void triqs_clef_auto_assign (expr && ex, RHS const & rhs) { ex << rhs;} - - template - void triqs_clef_auto_assign (expr const & ex, RHS const & rhs) { ex << rhs;} - - // The case A(x_,y_) = RHS : we form the function (make_function) and call auto_assign (by ADL) - template - void operator<<(expr...> && ex, RHS && rhs) { - triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); - } - template - void operator<<(expr...> const & ex, RHS && rhs) { - triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); - } - template - void operator<<(expr...> & ex, RHS && rhs) { - triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); - } - - // any other case e.g. f(x_+y_) = RHS etc .... which makes no sense : compiler will stop - template - void operator<<(expr && ex, RHS && rhs) = delete; - template - void operator<<(expr const & ex, RHS && rhs) = delete; - - /* --------------------------------------------------------------------------------------------------- - * Auto assign for [] - * --------------------------------------------------------------------------------------------------- */ - - // by default it is deleted = not implemented : every class has to define it... - template void triqs_clef_auto_assign_subscript (T,F) = delete; - - // remove the ref_wrapper, terminal ... - template void triqs_clef_auto_assign_subscript (std::reference_wrapper R ,F && f) - { triqs_clef_auto_assign_subscript(R.get(),std::forward(f));} - template void triqs_clef_auto_assign_subscript (expr const & t,F && f) - { triqs_clef_auto_assign_subscript(std::get<0>(t.childs),std::forward(f));} - - // auto assign of an expr ? (for chain calls) : just reuse the same operator - template - void triqs_clef_auto_assign_subscript (expr && ex, RHS const & rhs) { ex << rhs;} - - template - void triqs_clef_auto_assign_subscript (expr const & ex, RHS const & rhs) { ex << rhs;} - - // Same thing for the [ ] - template - void operator<<(expr...> const & ex, RHS && rhs) { - triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); - } - template - void operator<<(expr...> && ex, RHS && rhs) { - triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); - } - - template - void operator<<(expr && ex, RHS && rhs) = delete; - - template - void operator<<(expr const & ex, RHS && rhs) = delete; - - /* -------------------------------------------------------------------------------------------------- - * Create a terminal node of an object. the from clone version force copying the object - * --------------------------------------------------------------------------------------------------- */ - - // make a node with the ref, unless it is an rvalue (which is moved). - template expr > - make_expr(T && x){ return {tags::terminal(), std::forward(x)};} - - // make a node from a copy of the object - template expr::type > - make_expr_from_clone(T && x){ return {tags::terminal(), std::forward(x)};} - - /* -------------------------------------------------------------------------------------------------- - * Create a call node of an object - * The object can be kept as a : a ref, a copy, a view - * --------------------------------------------------------------------------------------------------- */ - - template struct arity { static constexpr int value =-1;}; - - namespace _result_of { - template< typename Obj, typename... Args > struct make_expr_call : - std::enable_if< is_any_lazy::value, expr, expr_storage_t ...> > { - static_assert (((arity::value==-1) || (arity::value == sizeof...(Args))), "Object called with a wrong number of arguments"); - }; - } - template< typename Obj, typename... Args > - typename _result_of::make_expr_call::type - make_expr_call(Obj&& obj, Args &&... args) { return {tags::function(),std::forward(obj), std::forward(args)...};} - - /* -------------------------------------------------------------------------------------------------- - * Create a [] call (subscript) node of an object - * The object can be kept as a : a ref, a copy, a view - * --------------------------------------------------------------------------------------------------- */ - - namespace _result_of { - template< typename Obj, typename Arg> struct make_expr_subscript : - std::enable_if< is_any_lazy::value, expr, expr_storage_t> > {}; - } - template< typename Obj, typename Arg> - typename _result_of::make_expr_subscript::type - make_expr_subscript(Obj&& obj, Arg && arg) { return {tags::subscript(),std::forward(obj), std::forward(arg)};} - - /* -------------------------------------------------------------------------------------------------- - * function class : stores any expression polymorphically - * f(x_,y_ ) = an expression associates this expression dynamically to f, which - * can then be used as a std::function of the same signature... - * --------------------------------------------------------------------------------------------------- */ - template class function; - - template class function : tags::function_class { - using std_function_type = std::function; - mutable std::shared_ptr _exp; // CLEAN THIS MUTABLE ? - mutable std::shared_ptr < std_function_type > _fnt_ptr; - public: - function():_fnt_ptr{std::make_shared ()}{} - - template - explicit function(Expr const& _e, X... x) - : _exp(std::make_shared(_e)), _fnt_ptr(new std_function_type(make_function(_e, x...))) {} - - ReturnType operator()(T const &... t) const { return (*_fnt_ptr)(t...);} - - template< typename... Args> - auto operator()( Args&&... args ) const DECL_AND_RETURN(make_expr_call (*this,std::forward(args)...)); - - template friend void triqs_clef_auto_assign (function const & x, RHS rhs) { - * (x._fnt_ptr) = std_function_type (rhs); - x._exp = std::make_shared::type> (rhs.ex); - } - - }; - template struct force_copy_in_expr > : std::true_type{}; - - /* -------------------------------------------------------------------------------------------------- - * The macro to make any function lazy - * TRIQS_CLEF_MAKE_FNT_LAZY (Arity,FunctionName ) : creates a new function in the triqs::lazy namespace - * taking expressions (at least one argument has to be an expression) - * The lookup happens by ADL, so IT MUST BE USED IN THE triqs::lazy namespace - * --------------------------------------------------------------------------------------------------- */ -#define TRIQS_CLEF_MAKE_FNT_LAZY(name) \ - struct name##_lazy_impl { \ - template auto operator()(A&&... a) const DECL_AND_RETURN(name(std::forward(a)...)); \ - }; \ - template auto name(A&&... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(), std::forward(a)...)); - - -#define TRIQS_CLEF_MAKE_FNT_LAZY_BIS(name) \ - struct name##_lazy_impl { \ - template auto operator()(A&&... a) const -> decltype(name(std::forward(a)...)); \ - }; \ - template auto name(A&&... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(), std::forward(a)...)); \ - template auto name##_lazy_impl::operator()(A&&... a) const DECL_AND_RETURN(name(std::forward(a)...)); - -#define TRIQS_CLEF_EXTEND_FNT_LAZY(FUN, TRAIT) \ - template \ - std::c14::enable_if_t::value, clef::expr_node_t> FUN(A&& a) { \ - return {clef::tags::function{}, clef::FUN##_lazy_impl{}, std::forward(a)}; \ - } - -#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY, name) \ - struct __clef_lazy_method_impl_##TY##_##name { \ - template auto operator()(X&& x, A&&... a) const DECL_AND_RETURN(x.name(std::forward(a)...)); \ - friend std::ostream& operator<<(std::ostream& out, __clef_lazy_method_impl_##TY##_##name const& x) { \ - return out << "apply_method:"<< BOOST_PP_STRINGIZE(name); \ - } \ - }; \ - template \ - auto name(A&&... a) DECL_AND_RETURN(make_expr_call(__clef_lazy_method_impl_##TY##_##name{}, *this, std::forward(a)...)); - -#define TRIQS_CLEF_IMPLEMENT_LAZY_CALL(...) \ - template \ - auto operator()(Args&&... args) const& DECL_AND_RETURN(make_expr_call(*this, std::forward(args)...)); \ - \ - template \ - auto operator()(Args&&... args) & DECL_AND_RETURN(make_expr_call(*this, std::forward(args)...)); \ - \ - template \ - auto operator()(Args&&... args) && DECL_AND_RETURN(make_expr_call(std::move(*this), std::forward(args)...)); - -/* -------------------------------------------------------------------------------------------------- - * sum of expressions - * --------------------------------------------------------------------------------------------------- */ - - // sum a function f on a domain D, using a simple foreach - template - auto sum_f_domain_impl(F const& f, D const& d) - -> std::c14::enable_if_t::value, decltype(f(*(d.begin())))> { - auto res = decltype(f(*(d.begin()))) {}; - using p_t = typename std::decay::type; - foreach(d, [&res, &f](p_t const& x) { res = res + f(x); }); - return res; - } - - TRIQS_CLEF_MAKE_FNT_LAZY(sum_f_domain_impl); - - // sum( expression, i = domain) - template auto sum(Expr const& f, clef::pair const& d) - DECL_AND_RETURN(sum_f_domain_impl(make_function(f, clef::placeholder()), d.rhs)); - - // two or more indices : sum recursively - template - auto sum(Expr const& f, clef::pair const& d0, clef::pair const& d1, clef::pair const&... d) - DECL_AND_RETURN(sum(sum(f, d0), d1, d...)); - -}} // namespace triqs::clef -#endif

(ex.childs), pairs...) +#define IMPL(z, NN, unused) \ + template struct evaluator_node_gal, Pairs...> { \ + static constexpr bool is_lazy = __or(evaluator::is_lazy...); \ + auto operator()(expr const& ex, Pairs const&... pairs) const \ + DECL_AND_RETURN(op_dispatch {}(BOOST_PP_ENUM(NN, AUX, nil))); \ + }; + BOOST_PP_REPEAT_FROM_TO(3,BOOST_PP_INC(TRIQS_CLEF_MAXNARGS), IMPL, nil); +#undef AUX +#undef IMPL + + template + struct evaluator, Pairs...> : evaluator_node_gal, Pairs...>{}; +#endif + + // The general eval function for expressions + template + auto eval(T const& ex, Pairs const&... pairs) DECL_AND_RETURN(evaluator()(ex, pairs...)); + + /* --------------------------------------------------------------------------------------------------- + * Apply a function object to all the leaves of the expression tree + * --------------------------------------------------------------------------------------------------- */ + + template struct apply_on_each_leaf_impl { + F f; + template std::c14::enable_if_t::value> operator()(T const& ex) { + tuple::for_each(ex.childs, *this); + } + template std::c14::enable_if_t::value> operator()(T const& x) { f(x); } + template std::c14::enable_if_t::value> operator()(std::reference_wrapper const& x) { + f(x.get()); + } + }; + + template void apply_on_each_leaf(F&& f, Expr const& ex) { + auto impl = apply_on_each_leaf_impl{std::forward(f)}; + impl(ex); + } + + /* --------------------------------------------------------------------------------------------------- + * make_function : transform an expression to a function + * --------------------------------------------------------------------------------------------------- */ + + template< typename Expr, int... Is> struct make_fun_impl { + Expr ex; // keep a copy of the expression + make_fun_impl(Expr const & ex_) : ex(ex_) {} + + template + auto operator()(Args &&... args) const + DECL_AND_RETURN( evaluator...>() ( ex, pair{std::forward(args)}...)); + }; + + // values of the ph, excluding the Is ... + template struct ph_filter; + template struct ph_filter { static constexpr ull_t value = ph_filter::value & (~ (1ull< struct ph_filter { static constexpr ull_t value = x; }; + + template< typename Expr, int... Is> struct ph_set > { static constexpr ull_t value = ph_filter ::value, Is...>::value;}; + template< typename Expr, int... Is> struct is_any_lazy > : std::integral_constant>::value !=0>{}; + template< typename Expr, int... Is> struct force_copy_in_expr > : std::true_type{}; + + template< typename Expr, typename ... Phs> + make_fun_impl::type,Phs::index...> + make_function(Expr && ex, Phs...) { return {ex}; } + + namespace result_of { + template< typename Expr, typename ... Phs> struct make_function { + using type = make_fun_impl::type, Phs::index...>; + }; + } + + template< typename Expr, int... Is,typename... Pairs> struct evaluator, Pairs...> { + using e_t = evaluator; + //using is_lazy = std::integral_constant>::value != ph_set::value>; + static constexpr bool is_lazy = (ph_set>::value != ph_set::value); + auto operator()(make_fun_impl const & f, Pairs const & ... pairs) const DECL_AND_RETURN( make_function( e_t()(f.ex, pairs...),placeholder()...)); + }; + + template struct ph_list {}; + template ph_list var( placeholder ...) { return {};} + + template + auto operator >> (ph_list, Expr const & ex) DECL_AND_RETURN( make_function(ex, placeholder()...)); + + /* -------------------------------------------------------------------------------------------------- + * make_function + * x_ >> expression is the same as make_function(expression,x) + * --------------------------------------------------------------------------------------------------- */ + + template + make_fun_impl operator >> (placeholder p, Expr&& ex) { return {ex}; } + + /* --------------------------------------------------------------------------------------------------- + * Auto assign for () + * --------------------------------------------------------------------------------------------------- */ + + // by default it is deleted = not implemented : every class has to define it... + template void triqs_clef_auto_assign (T,F) = delete; + + // remove the ref_wrapper, terminal ... + template void triqs_clef_auto_assign (std::reference_wrapper R ,F && f) { triqs_clef_auto_assign(R.get(),std::forward(f));} + template void triqs_clef_auto_assign (expr const & t,F && f) { triqs_clef_auto_assign(std::get<0>(t.childs),std::forward(f));} + + // auto assign of an expr ? (for chain calls) : just reuse the same operator + template + void triqs_clef_auto_assign (expr && ex, RHS const & rhs) { ex << rhs;} + + template + void triqs_clef_auto_assign (expr const & ex, RHS const & rhs) { ex << rhs;} + + // The case A(x_,y_) = RHS : we form the function (make_function) and call auto_assign (by ADL) + template + void operator<<(expr...> && ex, RHS && rhs) { + triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); + } + template + void operator<<(expr...> const & ex, RHS && rhs) { + triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); + } + template + void operator<<(expr...> & ex, RHS && rhs) { + triqs_clef_auto_assign(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); + } + + // any other case e.g. f(x_+y_) = RHS etc .... which makes no sense : compiler will stop + template + void operator<<(expr && ex, RHS && rhs) = delete; + template + void operator<<(expr const & ex, RHS && rhs) = delete; + + /* --------------------------------------------------------------------------------------------------- + * Auto assign for [] + * --------------------------------------------------------------------------------------------------- */ + + // by default it is deleted = not implemented : every class has to define it... + template void triqs_clef_auto_assign_subscript (T,F) = delete; + + // remove the ref_wrapper, terminal ... + template void triqs_clef_auto_assign_subscript (std::reference_wrapper R ,F && f) + { triqs_clef_auto_assign_subscript(R.get(),std::forward(f));} + template void triqs_clef_auto_assign_subscript (expr const & t,F && f) + { triqs_clef_auto_assign_subscript(std::get<0>(t.childs),std::forward(f));} + + // auto assign of an expr ? (for chain calls) : just reuse the same operator + template + void triqs_clef_auto_assign_subscript (expr && ex, RHS const & rhs) { ex << rhs;} + + template + void triqs_clef_auto_assign_subscript (expr const & ex, RHS const & rhs) { ex << rhs;} + + // Same thing for the [ ] + template + void operator<<(expr...> const & ex, RHS && rhs) { + triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); + } + template + void operator<<(expr...> && ex, RHS && rhs) { + triqs_clef_auto_assign_subscript(std::get<0>(ex.childs), make_function(std::forward(rhs), placeholder()...)); + } + + template + void operator<<(expr && ex, RHS && rhs) = delete; + + template + void operator<<(expr const & ex, RHS && rhs) = delete; + + /* -------------------------------------------------------------------------------------------------- + * Create a terminal node of an object. the from clone version force copying the object + * --------------------------------------------------------------------------------------------------- */ + + // make a node with the ref, unless it is an rvalue (which is moved). + template expr > + make_expr(T && x){ return {tags::terminal(), std::forward(x)};} + + // make a node from a copy of the object + template expr::type > + make_expr_from_clone(T && x){ return {tags::terminal(), std::forward(x)};} + + /* -------------------------------------------------------------------------------------------------- + * Create a call node of an object + * The object can be kept as a : a ref, a copy, a view + * --------------------------------------------------------------------------------------------------- */ + + template struct arity { static constexpr int value =-1;}; + + namespace _result_of { + template< typename Obj, typename... Args > struct make_expr_call : + std::enable_if< is_any_lazy::value, expr, expr_storage_t ...> > { + static_assert (((arity::value==-1) || (arity::value == sizeof...(Args))), "Object called with a wrong number of arguments"); + }; + } + template< typename Obj, typename... Args > + typename _result_of::make_expr_call::type + make_expr_call(Obj&& obj, Args &&... args) { return {tags::function(),std::forward(obj), std::forward(args)...};} + + /* -------------------------------------------------------------------------------------------------- + * Create a [] call (subscript) node of an object + * The object can be kept as a : a ref, a copy, a view + * --------------------------------------------------------------------------------------------------- */ + + namespace _result_of { + template< typename Obj, typename Arg> struct make_expr_subscript : + std::enable_if< is_any_lazy::value, expr, expr_storage_t> > {}; + } + template< typename Obj, typename Arg> + typename _result_of::make_expr_subscript::type + make_expr_subscript(Obj&& obj, Arg && arg) { return {tags::subscript(),std::forward(obj), std::forward(arg)};} + + /* -------------------------------------------------------------------------------------------------- + * function class : stores any expression polymorphically + * f(x_,y_ ) = an expression associates this expression dynamically to f, which + * can then be used as a std::function of the same signature... + * --------------------------------------------------------------------------------------------------- */ + template class function; + + template class function : tags::function_class { + using std_function_type = std::function; + mutable std::shared_ptr _exp; // CLEAN THIS MUTABLE ? + mutable std::shared_ptr < std_function_type > _fnt_ptr; + public: + function():_fnt_ptr{std::make_shared ()}{} + + template + explicit function(Expr const& _e, X... x) + : _exp(std::make_shared(_e)), _fnt_ptr(new std_function_type(make_function(_e, x...))) {} + + ReturnType operator()(T const &... t) const { return (*_fnt_ptr)(t...);} + + template< typename... Args> + auto operator()( Args&&... args ) const DECL_AND_RETURN(make_expr_call (*this,std::forward(args)...)); + + template friend void triqs_clef_auto_assign (function const & x, RHS rhs) { + * (x._fnt_ptr) = std_function_type (rhs); + x._exp = std::make_shared::type> (rhs.ex); + } + + }; + template struct force_copy_in_expr > : std::true_type{}; + + /* -------------------------------------------------------------------------------------------------- + * The macro to make any function lazy + * TRIQS_CLEF_MAKE_FNT_LAZY (Arity,FunctionName ) : creates a new function in the triqs::lazy namespace + * taking expressions (at least one argument has to be an expression) + * The lookup happens by ADL, so IT MUST BE USED IN THE triqs::lazy namespace + * --------------------------------------------------------------------------------------------------- */ +#define TRIQS_CLEF_MAKE_FNT_LAZY(name) \ + struct name##_lazy_impl { \ + template auto operator()(A&&... a) const DECL_AND_RETURN(name(std::forward(a)...)); \ + }; \ + template auto name(A&&... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(), std::forward(a)...)); + + +#define TRIQS_CLEF_MAKE_FNT_LAZY_BIS(name) \ + struct name##_lazy_impl { \ + template auto operator()(A&&... a) const -> decltype(name(std::forward(a)...)); \ + }; \ + template auto name(A&&... a) DECL_AND_RETURN(make_expr_call(name##_lazy_impl(), std::forward(a)...)); \ + template auto name##_lazy_impl::operator()(A&&... a) const DECL_AND_RETURN(name(std::forward(a)...)); + +#define TRIQS_CLEF_EXTEND_FNT_LAZY(FUN, TRAIT) \ + template \ + std::c14::enable_if_t::value, clef::expr_node_t> FUN(A&& a) { \ + return {clef::tags::function{}, clef::FUN##_lazy_impl{}, std::forward(a)}; \ + } + +#define TRIQS_CLEF_IMPLEMENT_LAZY_METHOD(TY, name) \ + struct __clef_lazy_method_impl_##TY##_##name { \ + template auto operator()(X&& x, A&&... a) const DECL_AND_RETURN(x.name(std::forward(a)...)); \ + friend std::ostream& operator<<(std::ostream& out, __clef_lazy_method_impl_##TY##_##name const& x) { \ + return out << "apply_method:"<< BOOST_PP_STRINGIZE(name); \ + } \ + }; \ + template \ + auto name(A&&... a) DECL_AND_RETURN(make_expr_call(__clef_lazy_method_impl_##TY##_##name{}, *this, std::forward(a)...)); + +#define TRIQS_CLEF_IMPLEMENT_LAZY_CALL(...) \ + template \ + auto operator()(Args&&... args) const& DECL_AND_RETURN(make_expr_call(*this, std::forward(args)...)); \ + \ + template \ + auto operator()(Args&&... args) & DECL_AND_RETURN(make_expr_call(*this, std::forward(args)...)); \ + \ + template \ + auto operator()(Args&&... args) && DECL_AND_RETURN(make_expr_call(std::move(*this), std::forward(args)...)); + +/* -------------------------------------------------------------------------------------------------- + * sum of expressions + * --------------------------------------------------------------------------------------------------- */ + + // sum a function f on a domain D, using a simple foreach + template + auto sum_f_domain_impl(F const& f, D const& d) + -> std::c14::enable_if_t::value, decltype(f(*(d.begin())))> { + auto res = decltype(f(*(d.begin()))) {}; + using p_t = typename std::decay::type; + foreach(d, [&res, &f](p_t const& x) { res = res + f(x); }); + return res; + } + + TRIQS_CLEF_MAKE_FNT_LAZY(sum_f_domain_impl); + + // sum( expression, i = domain) + template auto sum(Expr const& f, clef::pair const& d) + DECL_AND_RETURN(sum_f_domain_impl(make_function(f, clef::placeholder()), d.rhs)); + + // two or more indices : sum recursively + template + auto sum(Expr const& f, clef::pair const& d0, clef::pair const& d1, clef::pair const&... d) + DECL_AND_RETURN(sum(sum(f, d0), d1, d...)); + +}} // namespace triqs::clef +#endif diff --git a/triqs/clef/clef.c14.hpp b/triqs/clef/clef.c14.hpp new file mode 100644 index 00000000..55755a4d --- /dev/null +++ b/triqs/clef/clef.c14.hpp @@ -0,0 +1,607 @@ +/******************************************************************************* + * + * TRIQS: a Toolbox for Research in Interacting Quantum Systems + * + * 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 + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * TRIQS is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * TRIQS. If not, see . + * + ******************************************************************************/ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define TRIQS_CLEF_MAXNARGS 8 + +namespace triqs { namespace clef { + using ull_t = unsigned long long; + namespace tags { struct function_class{}; struct function{}; struct subscript{}; struct terminal{}; struct if_else{}; struct unary_op{}; struct binary_op{}; } + + // Compute the type to put in the expression tree. + // If T is a lvalue reference, pack it into a reference_wrapper, unless force_copy_in_expr::value == true + // If T is an rvalue reference, we store it as the type (using move semantics). + template struct force_copy_in_expr : std::false_type{}; + template struct force_copy_in_expr : force_copy_in_expr{}; + + template< class T> struct expr_storage_impl {using type=T;}; + template< class T> struct expr_storage_impl : std::conditional::value, typename std::remove_const::type ,std::reference_wrapper>{}; + template< class T> struct expr_storage_impl {using type=T;}; + template< class T> struct expr_storage_impl {using type=T;}; + template< class T> struct expr_storage_impl {using type=T;}; + + template using expr_storage_t = typename expr_storage_impl::type; // helper type + + /* --------------------------------------------------------------------------------------------------- + * Placeholder and corresponding traits + * --------------------------------------------------------------------------------------------------- */ + template struct pair; // forward + + // a placeholder is an empty struct, labelled by an int. + template struct placeholder { + static_assert( (N>=0) && (N<64) , "Placeholder number limited to [0,63]"); + static constexpr int index = N; + template pair operator = (RHS && rhs) { return {std::forward(rhs)};} + }; + + // placeholder will always be copied (they are empty anyway). + template struct force_copy_in_expr> : std::true_type {}; + + // represent a couple (placeholder, value). + template struct pair { + U rhs; + static constexpr int p = N; + using value_type = typename remove_cv_ref::type; + }; + + // ph_set is a trait that given a pack of type, returns the set of placeholders they contain + // it returns a int in binary coding : bit N in the int is 1 iif at least one T is lazy and contains placeholder + template struct ph_set; + template struct ph_set{static constexpr ull_t value= ph_set::value| ph_set::value;}; + template struct ph_set {static constexpr ull_t value= 0;}; + template struct ph_set> {static constexpr ull_t value= 1ull< struct ph_set > : ph_set>{}; + + // in_any_lazy : trait to detect if any of Args is a lazy expression + template struct is_any_lazy : std::false_type {}; + template struct is_any_lazy > : std::true_type {}; + template struct is_any_lazy< T > : std::false_type {}; + template struct is_any_lazy< T&& > : is_any_lazy {}; + template struct is_any_lazy< T& > : is_any_lazy {}; + template struct is_any_lazy< T const > : is_any_lazy {}; + template struct is_any_lazy : + std::integral_constant::value || is_any_lazy::value> {}; + + template + constexpr bool ClefExpression() { return is_any_lazy::value;} + + template struct is_clef_expression : is_any_lazy{}; + + /* --------------------------------------------------------------------------------------------------- + * Node of the expression tree + * --------------------------------------------------------------------------------------------------- */ + template struct expr { + // T can be U, U & (a reference or a value). + using childs_t = std::tuple; + childs_t childs; + expr(expr const & x) = default; + expr(expr && x) noexcept : childs(std::move(x.childs)) {} + // a constructor with the Tag make it unambiguous with other constructors... + template expr(Tag, Args&&...args) : childs(std::forward(args)...) {} + // [] returns a new lazy expression, with one more layer + template + expr > operator[](Args && args) const + { return {tags::subscript(), *this,std::forward(args)};} + // () also ... + template< typename... Args > + expr...> operator()(Args && ... args) const + { return {tags::function(), *this,std::forward(args)...};} + // assignement is in general deleted + expr & operator= (expr const &) = delete; // no ordinary assignment + expr & operator= (expr &&) = default; // move assign ok + // however, this is ok in the case f(i,j) = expr, where f is a clef::function + template + ENABLE_IF(std::is_base_of::type>) + operator= (RHS const & rhs) { *this << rhs;} + template + DISABLE_IF(std::is_base_of::type>) + operator= (RHS const & rhs) = delete; + }; + // set some traits + template struct ph_set< expr > : ph_set {}; + template struct is_any_lazy< expr >: std::true_type {}; + // if we want that subexpression are copied ? + template struct force_copy_in_expr< expr > : std::true_type{}; + + template using expr_node_t = expr...>; + + /* --------------------------------------------------------------------------------------------------- + * The basic operations put in a template.... + * --------------------------------------------------------------------------------------------------- */ + template struct operation; + + // a little function to clean the reference_wrapper + template U _cl(U && x) { return std::forward(x);} + template decltype(auto) _cl(std::reference_wrapper x) { return x.get();} + + /// Terminal + template<> struct operation { template L operator()(L&& l) const { return std::forward(l);} }; + + /// Function call + template<> struct operation { + template + decltype(auto) operator()(F&& f, Args&&... args) const { return _cl(std::forward(f))(_cl(std::forward(args))...);} + }; + + /// [ ] Call + template<> struct operation { + template + decltype(auto) operator()(F&& f, Args&& args) const { return _cl(std::forward(f))[_cl(std::forward(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 \ + std14::enable_if_t::value, expr, expr_storage_t>> operator OP(L&& l, R&& r) { \ + return {tags::TAG(), std::forward(l), std::forward(r)}; \ + } \ + template <> struct operation { \ + template decltype(auto) operator()(L&& l, R&& r) const { \ + return _cl(std::forward(l)) OP _cl(std::forward(r)); \ + } \ + }; + + TRIQS_CLEF_OPERATION(plus, +); + TRIQS_CLEF_OPERATION(minus, -); + TRIQS_CLEF_OPERATION(multiplies, *); + TRIQS_CLEF_OPERATION(divides, /); + TRIQS_CLEF_OPERATION(greater, >); + TRIQS_CLEF_OPERATION(less, <); + TRIQS_CLEF_OPERATION(leq, <=); + TRIQS_CLEF_OPERATION(geq, >=); + TRIQS_CLEF_OPERATION(eq, ==); +#undef TRIQS_CLEF_OPERATION + + // all unary operators.... +#define TRIQS_CLEF_OPERATION(TAG, OP) \ + namespace tags { \ + struct TAG : unary_op { \ + static const char* name() { return BOOST_PP_STRINGIZE(OP); } \ + }; \ + } \ + template std14::enable_if_t::value, expr>> operator OP(L&& l) { \ + return {tags::TAG(), std::forward(l)}; \ + } \ + template <> struct operation { \ + template decltype(auto) operator()(L&& l) const { return OP _cl(std::forward(l)); } \ + }; + + TRIQS_CLEF_OPERATION(negate, -); + TRIQS_CLEF_OPERATION(loginot, !); +#undef TRIQS_CLEF_OPERATION + + /// the only ternary node : expression if + template<> struct operation { + // A and B MUST be the same + template A operator()(C const & c, A const & a, B const & b) const {return _cl(c) ? _cl(a): _cl(b);} + //template auto operator()(C const & c, A const & a, B const & b) const DECL_AND_RETURN (_cl(c) ? _cl(a): _cl(b)); + }; + // operator is : if_else( Condition, A, B) + template + expr,expr_storage_t,expr_storage_t> + if_else(C && c, A && a, B && b) { return {tags::if_else(),std::forward(c),std::forward(a),std::forward(b)};} + + /* --------------------------------------------------------------------------------------------------- + * Evaluation of the expression tree. + * --------------------------------------------------------------------------------------------------- */ + + constexpr bool __or() { return false;} + template constexpr bool __or(bool b, B... bs) { return b || __or(bs...); } + + // Generic case : do nothing (for the leaf of the tree including placeholder) + template struct evaluator { + static constexpr bool is_lazy = is_any_lazy::value; + T const & operator()(T const& k, Pairs const&... pairs) const { return k; } + }; + + // The general eval function for expressions : declaration only + template decltype(auto) eval(T const& ex, Pairs const&... pairs); + + // placeholder + template struct evaluator, pair, Pairs...> { + using eval_t = evaluator, Pairs...>; + static constexpr bool is_lazy = eval_t::is_lazy; + decltype(auto) operator()(placeholder, pair const&, Pairs const&... pairs) const { return eval_t()(placeholder(), pairs...);} + }; + + template struct evaluator, pair, Pairs...> { + static constexpr bool is_lazy = false; + T operator()(placeholder, pair const& p, Pairs const&...) const { return p.rhs; } + }; + + // any object hold by reference wrapper is redirected to the evaluator of the object + template struct evaluator, Contexts...> { + static constexpr bool is_lazy = false; + decltype(auto) operator()(std::reference_wrapper const& x, Contexts const&... contexts) const { return eval(x.get(), contexts...);} + }; + + // dispatching the evaluation : if lazy, we make a new clef expression, if not we call the operation + template struct op_dispatch; + + template struct op_dispatch { + template expr...> operator()(Args&&... args) const { + return {Tag(), std::forward(args)...}; + } + }; + + template struct op_dispatch { + template decltype(auto) operator()(Args&&... args) const { + return operation()(std::forward(args)...); + } + }; + + // apply_compose not ready +#ifdef TRIQS_USE_C14_DRAFT__ + // general expr node + template struct evaluator, Pairs...> { + + static constexpr bool is_lazy = __or(evaluator::is_lazy...); + + decltype(auto) operator()(expr const& ex, Pairs const&... pairs) const { + auto eval_in_context = [&pairs...](auto const& _child) { return eval(_child, pairs...); }; + return tuple::apply_compose(op_dispatch{}, eval_in_context, ex.childs); + } + }; +#else + // WORKAROUND FOR C++11 compilers + template struct evaluator_node_gal; + + template struct evaluator_node_gal<1, expr, Pairs...> { + static constexpr bool is_lazy = __or(evaluator::is_lazy...); + auto operator()(expr const& ex, Pairs const&... pairs) const + DECL_AND_RETURN(op_dispatch {}(eval(std::get<0>(ex.childs), pairs...))); + }; + + template struct evaluator_node_gal<2, expr, Pairs...> { + static constexpr bool is_lazy = __or(evaluator::is_lazy...); + auto operator()(expr const& ex, Pairs const&... pairs) const + DECL_AND_RETURN(op_dispatch {}(eval(std::get<0>(ex.childs), pairs...), eval(std::get<1>(ex.childs), pairs...))); + }; + +#define TRIQS_CLEF_MAXNARGS 8 + +// the general case for more than 2 nodes. I put 1 and 2 nodes apart, just because it is the most frequent +// and macros yield more obscure error messages in case of a pb ... +#define AUX(z, p, unused) eval(std::get