/******************************************************************************* * * TRIQS: a Toolbox for Research in Interacting Quantum Systems * * Copyright (C) 2012 by M. Ferrero, 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_GF_EXPR_H #define TRIQS_GF_EXPR_H #include namespace triqs { namespace gfs { using utility::is_in_ZRC; using utility::remove_rvalue_ref; namespace gfs_expr_tools { // a wrapper for scalars template struct scalar_wrap { using variable_t = void; using target_t = void; using option_t = void; S s; template scalar_wrap(T &&x) : s(std::forward(x)) {} S singularity() const { return s; } template S operator[](KeyType &&key) const { return s; } template inline S operator()(Args &&... args) const { return s; } friend std::ostream &operator<<(std::ostream &sout, scalar_wrap const &expr) { return sout << expr.s; } }; // Combine the two meshes of LHS and RHS : need to specialize where there is a scalar struct combine_mesh { template auto operator()(L &&l, R &&r) const -> decltype(std::forward(l).mesh()) { if (!(l.mesh() == r.mesh())) TRIQS_RUNTIME_ERROR << "Mesh mismatch : in Green Function Expression " << l.mesh() << " vs" << r.mesh(); return std::forward(l).mesh(); } template auto operator()(scalar_wrap const &, R &&r) const DECL_AND_RETURN(std::forward(r).mesh()); template auto operator()(L &&l, scalar_wrap const &) const DECL_AND_RETURN(std::forward(l).mesh()); }; // Same thing to get the data shape // NB : could be unified to one combine, where F is a functor, but an easy usage requires polymorphic lambda ... struct combine_shape { template auto operator()(L &&l, R &&r) const -> decltype(get_gf_data_shape(std::forward(l))) { if (!(get_gf_data_shape(l) == get_gf_data_shape(r))) TRIQS_RUNTIME_ERROR << "Shape mismatch in Green Function Expression: " << get_gf_data_shape(l) << " vs " << get_gf_data_shape(r); return get_gf_data_shape(std::forward(l)); } template auto operator()(scalar_wrap const &, R &&r) const DECL_AND_RETURN(get_gf_data_shape(std::forward(r))); template auto operator()(L &&l, scalar_wrap const &) const DECL_AND_RETURN(get_gf_data_shape(std::forward(l))); }; template using node_t = std14::conditional_t::value, scalar_wrap, typename remove_rvalue_ref::type>; template struct _or_ {using type=void ;}; template struct _or_ {using type=A ;}; template struct _or_ {using type=A ;}; template struct _or_ {using type=A ;}; template <> struct _or_ {using type=void ;}; }// gfs_expr_tools template struct gf_expr : TRIQS_CONCEPT_TAG_NAME(ImmutableGreenFunction) { using L_t = typename std::remove_reference::type; using R_t = typename std::remove_reference::type; using variable_t = typename gfs_expr_tools::_or_::type; using target_t = typename gfs_expr_tools::_or_::type; using option_t = typename gfs_expr_tools::_or_::type; static_assert(!std::is_same::value, "Cannot combine two gf expressions with different variables"); static_assert(!std::is_same::value, "Cannot combine two gf expressions with different target"); L l; R r; template gf_expr(LL &&l_, RR &&r_) : l(std::forward(l_)), r(std::forward(r_)) {} auto mesh() const DECL_AND_RETURN(gfs_expr_tools::combine_mesh()(l, r)); auto singularity() const DECL_AND_RETURN(utility::operation()(l.singularity(), r.singularity())); template auto operator[](KeyType &&key) const DECL_AND_RETURN(utility::operation()(l[std::forward(key)], r[std::forward(key)])); template auto operator()(Args &&... args) const DECL_AND_RETURN(utility::operation()(l(std::forward(args)...), r(std::forward(args)...))); friend std::ostream &operator<<(std::ostream &sout, gf_expr const &expr) { return sout << "(" << expr.l << " " << utility::operation::name << " " << expr.r << ")"; } }; template auto get_gf_data_shape(gf_expr const &g) RETURN(gfs_expr_tools::combine_shape()(g.l, g.r)); // ------------------------------------------------------------------- // a special case : the unary operator ! template struct gf_unary_m_expr : TRIQS_CONCEPT_TAG_NAME(ImmutableGreenFunction) { using L_t = typename std::remove_reference::type; using variable_t = typename L_t::variable_t; using target_t = typename L_t::target_t; using option_t = typename L_t::option_t; L l; template gf_unary_m_expr(LL && l_) : l(std::forward(l_)) {} auto mesh() const DECL_AND_RETURN(l.mesh()); auto singularity() const DECL_AND_RETURN(l.singularity()); template auto operator[](KeyType&& key) const DECL_AND_RETURN( -l[key]); template auto operator()(Args && ... args) const DECL_AND_RETURN( -l(std::forward(args)...)); friend std::ostream &operator <<(std::ostream &sout, gf_unary_m_expr const &expr){return sout << '-'< AUTO_DECL get_gf_data_shape(gf_unary_m_expr const &g) RETURN(get_gf_data_shape(g.l)); // ------------------------------------------------------------------- // Now we can define all the C++ operators ... #define DEFINE_OPERATOR(TAG, OP, TRAIT1, TRAIT2) \ template\ std14::enable_if_t::value && TRAIT2 ::value, \ gf_expr, gfs_expr_tools::node_t>>\ operator OP (A1 && a1, A2 && a2) { return {std::forward(a1),std::forward(a2)};} DEFINE_OPERATOR(plus, +, ImmutableGreenFunction,ImmutableGreenFunction); DEFINE_OPERATOR(minus, -, ImmutableGreenFunction,ImmutableGreenFunction); DEFINE_OPERATOR(multiplies, *, ImmutableGreenFunction,ImmutableGreenFunction); DEFINE_OPERATOR(multiplies, *, is_in_ZRC,ImmutableGreenFunction); DEFINE_OPERATOR(multiplies, *, ImmutableGreenFunction,is_in_ZRC); DEFINE_OPERATOR(divides, /, ImmutableGreenFunction,ImmutableGreenFunction); DEFINE_OPERATOR(divides, /, is_in_ZRC,ImmutableGreenFunction); DEFINE_OPERATOR(divides, /, ImmutableGreenFunction,is_in_ZRC); #undef DEFINE_OPERATOR // the unary is special template std14::enable_if_t::value, gf_unary_m_expr>> operator-(A1 &&a1) { return {std::forward(a1)}; } // Now the inplace operator. Because of expression template, there are useless for speed // we implement them trivially. #define DEFINE_OPERATOR(OP1, OP2) \ template \ void operator OP1(gf_view g, T const &x) { \ g = g OP2 x; \ } \ template \ void operator OP1(gf &g, T const &x) { \ g = g OP2 x; \ } DEFINE_OPERATOR(+=, +); DEFINE_OPERATOR(-=, -); DEFINE_OPERATOR(*=, *); DEFINE_OPERATOR(/=, / ); #undef DEFINE_OPERATOR }}//namespace triqs::gf #endif