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 + 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
(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