From 9790fe8bd09f09b68026a8ea83aa00eff4cc696c Mon Sep 17 00:00:00 2001 From: Olivier Parcollet Date: Fri, 6 Sep 2013 15:53:28 +0200 Subject: [PATCH] Work on gf - clean curry. - start testing. --- test/triqs/gf/c++11/curry_and_fourier.cpp | 45 ++++++ test/triqs/gf/c++11/gf_re_im_freq_time.cpp | 4 +- test/triqs/utility/tuple_tools.cpp | 58 +++++++- triqs/gfs/curry.hpp | 135 +++++------------ triqs/gfs/gf.hpp | 13 +- triqs/gfs/local/fourier_matsubara.hpp | 7 +- triqs/gfs/local/fourier_real.hpp | 6 +- triqs/gfs/product.hpp | 3 + triqs/utility/tuple_tools.hpp | 161 ++++++++++++++++++++- 9 files changed, 320 insertions(+), 112 deletions(-) create mode 100644 test/triqs/gf/c++11/curry_and_fourier.cpp diff --git a/test/triqs/gf/c++11/curry_and_fourier.cpp b/test/triqs/gf/c++11/curry_and_fourier.cpp new file mode 100644 index 00000000..49d263bb --- /dev/null +++ b/test/triqs/gf/c++11/curry_and_fourier.cpp @@ -0,0 +1,45 @@ +#define TRIQS_ARRAYS_ENFORCE_BOUNDCHECK + +#include +#include +#include + +#include +#include +#include + +using namespace triqs::gfs; + +int main() { + +try { + double beta =1.; + double tmin=0.; + double tmax=10; + double wmin=0.; + double wmax=1.0; + int n_re_freq=100; + int n_im_freq=100; + int Nt=100; + + triqs::clef::placeholder<0> w_; + triqs::clef::placeholder<1> wn_; + triqs::clef::placeholder<2> tau_; + + auto G_w_wn = make_gf, scalar_valued>( gf_mesh(wmin, wmax, n_re_freq), gf_mesh(wmin, wmax, n_re_freq)); + auto G_w_tau = make_gf, scalar_valued>( gf_mesh(wmin, wmax, n_re_freq), gf_mesh(-tmax, tmax, Nt)); + + G_w_wn(w_,wn_)<<1/(wn_-1)/( pow(w_,3) ); + G_w_tau(w_,tau_)<< exp( -2*tau_ ) / (w_*w_ + 1 ); + + auto G_w_wn_curry0 = curry<0>(G_w_wn); + auto G_w_tau_curry0 = curry<0>(G_w_tau); + + for (auto const & w : G_w_wn_curry0.mesh()) G_w_wn_curry0[w] = lazy_fourier(G_w_tau_curry0[w]); + + G_w_wn_curry0[w_] << lazy_fourier(G_w_tau_curry0[w_]); + + curry<0>(G_w_wn) [w_] << lazy_fourier(curry<0>(G_w_tau)[w_]); +} +catch(std::exception const & e ) { std::cout << "error "<< e.what()<< std::endl;} +} diff --git a/test/triqs/gf/c++11/gf_re_im_freq_time.cpp b/test/triqs/gf/c++11/gf_re_im_freq_time.cpp index 486c2c03..7a10834c 100644 --- a/test/triqs/gf/c++11/gf_re_im_freq_time.cpp +++ b/test/triqs/gf/c++11/gf_re_im_freq_time.cpp @@ -48,6 +48,7 @@ try { auto G_w_wn2_view = G_w_wn2(); auto G_w_wn_sl0_a = partial_eval<0>(G_w_wn2(), std::make_tuple(8)); + static_assert(std::is_same::type, const gf_mesh>::value, "oops"); //auto G_w_wn_curry0_a = curry0(G_w_wn2); //auto G_w_wn_sl0_a = slice_mesh0(G_w_wn2(), 8); @@ -84,6 +85,8 @@ try { std::cout << "curry no"<< G_w_wn.on_mesh(8,3) << std::endl ; auto G_w_wn_curry0 = curry<0>(G_w_wn2); + static_assert(std::is_same::type, const gf_mesh>::value, "oops"); + static_assert(std::is_same::type, const gf_mesh>::value, "oops"); auto G_w_wn_curry1 = curry<1>(G_w_wn2); auto G_w_wn2_view2 = G_w_wn2(); @@ -91,7 +94,6 @@ try { std::cout << " curry "< std::string my_print_str(int x, int y) { std::stringstream fs; fs << "the string is "<< x<< " " << y; return fs.str();} +namespace triqs { namespace tuple { + +}} int main(int argc, char **argv) { @@ -99,11 +102,64 @@ int main(int argc, char **argv) { } { // to mini_vector - + auto t = std::make_tuple(1,2,3.4); auto m = triqs::utility::tuple_to_mini_vector(t); std::cout << m<< std::endl ; } + + { // filter + std::cout << " ----- filter ----"<< std::endl ; + auto t= std::make_tuple(0,1,2,3,4,"=5"); + std::cout << "filter "<< t << triqs::tuple::filter<0,2,3>(t)<< std::endl; + std::cout << "filter "<< t << triqs::tuple::filter<1,3,5>(t)<< std::endl; + + std::cout << "filter out "<< t << triqs::tuple::filter_out<0,2,3>(t)<< std::endl; + std::cout << "filter out "<< t << triqs::tuple::filter_out<1,3,5>(t)<< std::endl; + + auto t2= std::make_tuple(0,1); + std::cout << "filter out "<< t2 << triqs::tuple::filter_out<0>(t2)<< std::endl; + + typedef typename triqs::tuple::filter_t_tr< decltype(t), 0,2,3>::type TY; + static_assert(std::is_same(t))>::value, "EEE"); + } + + { // filter + std::cout << " ----- inverse filter ----"<< std::endl ; + auto t= std::make_tuple(1,4,5); + auto s = std::string{"--"}; + { + auto r = triqs::tuple::inverse_filter<6,0,2,3>(t, s); + std::cout << "inverse filter "<< t << r<< triqs::tuple::filter<0,2,3>(r)<(t, s); + std::cout << "inverse filter "<< t << r<< triqs::tuple::filter<0,2,5>(r)<(t, s); + std::cout << "inverse filter "<< t << r<< triqs::tuple::filter<0,2,5>(r)<(t, s); + std::cout << "inverse filter out "<< t << r<< triqs::tuple::filter_out<0,2,3>(r)<(t, s); + std::cout << "inverse filter out "<< t << r<< triqs::tuple::filter_out<0,2,3,5>(r)<(t, s); + std::cout << "inverse filter out "<< t << r<< triqs::tuple::filter_out<0,2,3,6>(r)<(t,s)<< std::endl; + std::cout << "replace 1,3,5"<< t << triqs::tuple::replace<1,3,5>(t,s)<< std::endl; + } + + } diff --git a/triqs/gfs/curry.hpp b/triqs/gfs/curry.hpp index 8a89bd3d..a5fe1e50 100644 --- a/triqs/gfs/curry.hpp +++ b/triqs/gfs/curry.hpp @@ -21,17 +21,15 @@ #ifndef TRIQS_GF_CURRY_H #define TRIQS_GF_CURRY_H #include "./product.hpp" - #ifndef TRIQS_COMPILER_IS_C11_COMPLIANT #error "This header requires a fully C++11 compliant compiler" #endif - namespace triqs { namespace gfs { template struct lambda_valued {}; namespace gfs_implementation { - + /// --------------------------- data access --------------------------------- template struct data_proxy,Opt> : data_proxy_lambda {}; @@ -41,124 +39,63 @@ namespace triqs { namespace gfs { template struct factories, lambda_valued, Opt> {}; - // detail - template struct cartesian_product_add_front; - template struct cartesian_product_add_front>{ typedef cartesian_product type; }; + /// --------------------------- partial_eval --------------------------------- + // partial_eval<0> (g, 1) returns : x -> g(1,x) + // partial_eval<1> (g, 3) returns : x -> g(x,3) - // ------------------------------------------------- - // Partial evaluation of the gf - // ------------------------------------------------- - // - // Given a cartesian_product of meshes (CP), and a compile time list of int (I) - // - metacompute the list of Ms without position those at position 0,2 (type) - // - provide 2 runtimes functions : - // - sl : given empty tuple () and a tuple (it) of indices - // return the tuple of indices and range, where range are at the position defined by I, - // and the indices in other places, in order. - // - m : returns from a CP object the corresponding tuple of meshes of the remaining meshes - // after partial eval (of the type computed by "type"). - // - auxiliary data : - // pos : position in the CP tuple (CP::size-1 ->0) - // ip : position in the tuple of indices (for sl) - // MP : accumulation of the final type metacomputed. - // - template struct pv_impl; - template struct pv_ : pv_impl,I...>{}; - - template struct pv_impl<-1, ip, CP, MP, I... > { - // the final type is a cartesian_product<...> if there is more than one mess - // and otherwise the only mesh remaining... (avoiding cartesian_product e.g. which makes little sense). - typedef typename std::conditional::type, MP>::type type; - template static T sl(T t, IT const & it) {return t;} - template static T m (T t, MT const & mt) {return t;} - }; + // a technical trait: from a tuple of mesh, return the mesh (either M if it is a tuple of size 1, or the corresponding cartesian_product). + template struct cart_prod_impl; + template using cart_prod = typename cart_prod_impl::type; + template struct cart_prod_impl> { using type = cartesian_product;}; + template struct cart_prod_impl> { typedef M type;}; //using type = M;}; - template struct pv_impl { - typedef pv_impl B; - typedef typename B::type type; - template static auto sl (T t, IT const & it) DECL_AND_RETURN( B::sl(triqs::tuple::push_front(t,arrays::range()),it)); - template static auto m (T t, MT const & mt) DECL_AND_RETURN( B::m(t,mt)); - }; + template auto rm_tuple_of_size_one(std::tuple const & t) DECL_AND_RETURN(t); + template auto rm_tuple_of_size_one(std::tuple const & t) DECL_AND_RETURN(std::get<0>(t)); - template struct pv_impl { - typedef typename cartesian_product_add_front::type, MP>::type MP2; - typedef pv_impl B; - typedef typename B::type type; - template static auto sl (T t, IT const & it) DECL_AND_RETURN( B::sl(triqs::tuple::push_front(t,std::get(it)),it)); - template static auto m (T t, MT const & mt) DECL_AND_RETURN( B::m (triqs::tuple::push_front(t,std::get(mt)),mt)); - }; - - // partial_eval<0> (g, 1) : returns : x -> g(1,x) - // partial_eval<1> (g, 3) : returns : x -> g(x,3) - // template - gf_view,pos...>::type ,Target, Opt> + gf_view< typename cart_prod_impl< triqs::tuple::filter_out_t, pos...>>::type ,Target, Opt> partial_eval(gf_impl< cartesian_product, Target,Opt,B> const & g, IT index) { + // meshes of the returned gf_view : just drop the mesh of the evaluated variables + auto meshes_tuple_partial = triqs::tuple::filter_out(g.mesh().components()); + // a view of the array of g, with the dimension sizeof...(Ms) auto arr = reinterpret_linear_array(g.mesh(),g.data()); - typedef pv_,pos...> pv_t; - typedef gf_view< typename pv_t::type,Target, Opt> r_t; - auto comp = pv_t::m(std::make_tuple(),g.mesh().components()); - auto arr_args = pv_t::sl(std::make_tuple(),index); - // generalize this get<0> ---> flatten the tuple (construct from a tuple of args...) - return r_t{ std::get<0>(comp), triqs::tuple::apply(arr, arr_args), typename r_t::singularity_non_view_t{}, typename r_t::symmetry_t{} }; + // now rebuild a tuple of the size sizeof...(Ms), containing the indices and range at the position of evaluated variables. + auto arr_args = triqs::tuple::inverse_filter(index, arrays::range()); + // from it, we make a slice of the array of g, corresponding to the data of the returned gf_view + auto arr2 = triqs::tuple::apply(arr, arr_args); + // finally, we build the view on this data. + using r_t = gf_view< cart_prod< triqs::tuple::filter_out_t, pos...>> ,Target, Opt>; + return r_t{ rm_tuple_of_size_one(meshes_tuple_partial), arr2, typename r_t::singularity_non_view_t{}, typename r_t::symmetry_t{} }; } + /// --------------------------- curry --------------------------------- + // curry<0>(g) returns : x-> y... -> g(x,y...) + // curry<1>(g) returns : y-> x,z... -> g(x,y,z...) + // to adapt the partial_eval as a polymorphic lambda (replace by a lambda in c++14) template struct curry_polymorphic_lambda { Gview g; - template - auto operator()(I ... i) const DECL_AND_RETURN( partial_eval(g,std::make_tuple(i...))); + template auto operator()(I ... i) const DECL_AND_RETURN(partial_eval(g,std::make_tuple(i...))); }; - // curry<0>(g) returns : x-> y... -> g(x,y...) - // curry<1>(g) returns : x-> y,z... -> g(y,x,z...) - // and so on + // curry function ... template - gf_view< typename pv_,pos...>::type, + gf_view,pos...> >, lambda_valued, Target,Opt>,pos...>>, Opt> curry (gf_impl, Target,Opt,B> const & g) { - auto comp = pv_,pos...>::m(std::make_tuple(),g.mesh().components()); - typedef gf_mesh< typename pv_,pos...>::type,Opt> m_t; - return {triqs::tuple::apply_construct(comp),curry_polymorphic_lambda, Target,Opt>, pos ...>{g}, nothing(), nothing()}; + // pick up the meshed corresponding to the curryed variables + auto meshes_tuple = triqs::tuple::filter(g.mesh().components()); + // building the view + return {rm_tuple_of_size_one(meshes_tuple),curry_polymorphic_lambda, Target,Opt>, pos ...>{g}, nothing(), nothing()}; + //using m_t = gf_mesh< cart_prod< triqs::tuple::filter_t,pos...>>>; + //return {triqs::tuple::apply_construct(meshes_tuple),curry_polymorphic_lambda, Target,Opt>, pos ...>{g}, nothing(), nothing()}; }; } // gf_implementation - using gfs_implementation::partial_eval; using gfs_implementation::curry; - - /// ----- first implementation - /* - // slicing on first arg - template - gf_view slice_mesh0 (gf_view< cartesian_product, scalar_valued,Opt> g, size_t index) { - auto arr = reinterpret_linear_array(g.mesh(),g.data()); - typedef gf_view r_t; - return { std::get<1>(g.mesh().components()), arr(index,arrays::range()), typename r_t::singularity_non_view_t{}, typename r_t::symmetry_t{} }; - } - - // slicing on first arg - template - gf_view slice_mesh1 (gf_view< cartesian_product, scalar_valued,Opt> g, size_t index) { - auto arr = reinterpret_linear_array(g.mesh(),g.data()); - typedef gf_view r_t; - return { std::get<0>(g.mesh().components()), arr(arrays::range(), index), typename r_t::singularity_non_view_t{}, typename r_t::symmetry_t{} }; - } - - - template struct curry_lambda0 { - Gview g; - auto operator()(size_t i) const DECL_AND_RETURN( slice_mesh0(g,i)); - }; - - template - gf_view, scalar_valued,Opt>>>, Opt> - curry0 (gf_impl, scalar_valued,Opt,B> const & g) { - return {std::get<0>(g.mesh().components()),curry_lambda0, scalar_valued,Opt>>{g}, nothing(), nothing()}; - }; - -*/ }} #endif + diff --git a/triqs/gfs/gf.hpp b/triqs/gfs/gf.hpp index f05ca47c..6c9c0f58 100644 --- a/triqs/gfs/gf.hpp +++ b/triqs/gfs/gf.hpp @@ -340,9 +340,9 @@ namespace triqs { namespace gfs { template gf_view(gf_impl const & g): B(g){} - template + template gf_view (typename B::mesh_t const & m, - D const & dat,T const & t,typename B::symmetry_t const & s, + D const & dat,typename B::singularity_view_t const & t,typename B::symmetry_t const & s, typename B::evaluator_t const &e = typename B::evaluator_t () ) : B(m,factory(dat),t,s,e) {} @@ -359,7 +359,7 @@ namespace triqs { namespace gfs { template gf_view & operator = (RHS const & rhs) { triqs_gf_view_assign_delegation(*this,rhs); return *this;} // Interaction with the CLEF library : auto assignment of the gf (gf(om_) << expression fills the functions by evaluation of expression) - template friend void triqs_clef_auto_assign (gf_view & g, RHS rhs) { + template friend void triqs_clef_auto_assign (gf_view g, RHS rhs) { // access to the data . Beware, we view it as a *matrix* NOT an array... (crucial for assignment to scalars !) g.triqs_clef_auto_assign_impl(rhs, typename std::is_base_of::type()); assign_from_expression(g.singularity(),rhs); @@ -367,6 +367,9 @@ namespace triqs { namespace gfs { // it uses the fact that tail_non_view_t can be casted into freq_infty } + // enable the writing g[om_] << .... also + template friend void triqs_clef_auto_assign_subscript (gf_view g, RHS rhs) { triqs_clef_auto_assign(g,rhs);} + private: template void triqs_clef_auto_assign_impl (RHS const & rhs, std::integral_constant) { for (auto const & w: this->mesh()) (*this)[w] = rhs(w); @@ -381,14 +384,14 @@ namespace triqs { namespace gfs { // delegate = so that I can overload it for specific RHS... template - DISABLE_IF(arrays::is_scalar) triqs_gf_view_assign_delegation( gf_view & g, RHS const & rhs) { + DISABLE_IF(arrays::is_scalar) triqs_gf_view_assign_delegation( gf_view g, RHS const & rhs) { if (!(g.mesh() == rhs.mesh())) TRIQS_RUNTIME_ERROR<<"Gf Assignment in View : incompatible mesh"; gf_view::data_proxy_t::assign_no_resize(g.data(),rhs.data()); g.singularity() = rhs.singularity(); } template - ENABLE_IF(arrays::is_scalar) triqs_gf_view_assign_delegation( gf_view & g, T const & x) { + ENABLE_IF(arrays::is_scalar) triqs_gf_view_assign_delegation( gf_view g, T const & x) { gf_view::data_proxy_t::assign_to_scalar(g.data(), x); g.singularity() = x; } diff --git a/triqs/gfs/local/fourier_matsubara.hpp b/triqs/gfs/local/fourier_matsubara.hpp index b4d99cf8..0baafa43 100644 --- a/triqs/gfs/local/fourier_matsubara.hpp +++ b/triqs/gfs/local/fourier_matsubara.hpp @@ -74,8 +74,11 @@ namespace triqs { namespace gfs { void triqs_gf_view_assign_delegation( gf_view g, gf_keeper const & L); void triqs_gf_view_assign_delegation( gf_view g, gf_keeper const & L); void triqs_gf_view_assign_delegation( gf_view g, gf_keeper const & L); - - +}} + +namespace triqs { namespace clef { +TRIQS_CLEF_MAKE_FNT_LAZY (lazy_fourier); +TRIQS_CLEF_MAKE_FNT_LAZY (lazy_inverse_fourier); }} #endif diff --git a/triqs/gfs/local/fourier_real.hpp b/triqs/gfs/local/fourier_real.hpp index 0fbcd8e3..d9f7981c 100644 --- a/triqs/gfs/local/fourier_real.hpp +++ b/triqs/gfs/local/fourier_real.hpp @@ -80,8 +80,10 @@ namespace triqs { namespace gfs { inline gf_keeper lazy_fourier (gf_view const & g) { return g;} inline gf_keeper lazy_inverse_fourier (gf_view const & g) { return g;} - void triqs_gf_view_assign_delegation( gf_view g, gf_keeper const & L); - void triqs_gf_view_assign_delegation( gf_view g, gf_keeper const & L); + void triqs_gf_view_assign_delegation( gf_view g, gf_keeper const & L); + void triqs_gf_view_assign_delegation( gf_view g, gf_keeper const & L); + void triqs_gf_view_assign_delegation( gf_view g, gf_keeper const & L); + void triqs_gf_view_assign_delegation( gf_view g, gf_keeper const & L); }} #endif diff --git a/triqs/gfs/product.hpp b/triqs/gfs/product.hpp index 4b6c870e..41c190ac 100644 --- a/triqs/gfs/product.hpp +++ b/triqs/gfs/product.hpp @@ -31,6 +31,9 @@ namespace triqs { namespace gfs { static constexpr size_t size = sizeof...(Ms); }; + // use alias + template struct cartesian_product > : cartesian_product{}; + // the mesh is simply a cartesian product template struct gf_mesh,Opt> : mesh_product< gf_mesh ... > { typedef mesh_product< gf_mesh ... > B; diff --git a/triqs/utility/tuple_tools.hpp b/triqs/utility/tuple_tools.hpp index 2bc12052..0a31c0af 100644 --- a/triqs/utility/tuple_tools.hpp +++ b/triqs/utility/tuple_tools.hpp @@ -32,7 +32,7 @@ namespace triqs { namespace tuple { * push_back (t,x) -> returns new tuple with x append at the end */ template - auto push_back(T const &t, X const &x) DECL_AND_RETURN ( std::tuple_cat(t,std::make_tuple(x))); + auto push_back(T && t, X &&x) DECL_AND_RETURN ( std::tuple_cat(std::forward(t),std::make_tuple(std::forward(x)))); /** * t : a tuple @@ -40,7 +40,7 @@ namespace triqs { namespace tuple { * push_front (t,x) -> returns new tuple with x append at the first position */ template - auto push_front(T const &t, X const &x) DECL_AND_RETURN ( std::tuple_cat(std::make_tuple(x),t)); + auto push_front(T && t, X &&x) DECL_AND_RETURN ( std::tuple_cat(std::make_tuple(std::forward(x)),std::forward(t))); /** * apply(f, t) @@ -264,6 +264,158 @@ namespace triqs { namespace tuple { template auto fold_on_zip (F && f,T1 const & t1, T2 const & t2, R && r) DECL_AND_RETURN( fold_on_zip_impl::value-1,T1,T2>()(std::forward(f),t1,t2,std::forward(r))); + /** + * filter(t) : + * Given a tuple t, and integers, returns the tuple where the elements at initial position I are dropped. + */ + + // pos = position in the tuple, c : counter tuplesize-1 ->0, I : position to filter + template struct filter_impl; + + // default case where pos != the first I : increase pos + template struct filter_impl : filter_impl {}; + + // when pos == first I + template struct filter_impl { + template auto operator() (TupleIn const & t, TupleOut && out) const + DECL_AND_RETURN( filter_impl() ( t, push_back(std::forward(out),std::get(t)))); + }; + + template struct filter_impl { + template TupleOut operator() (TupleIn const & t, TupleOut && out) const {return out;} + }; + + template + auto filter(Tu const & tu) DECL_AND_RETURN ( filter_impl<0,std::tuple_size::value-1, I...>()(tu, std::make_tuple())); + + template struct filter_t_tr : std::result_of< filter_impl<0,std::tuple_size::value-1, I...>( Tu, std::tuple<>)>{}; + +#ifdef TRIQS_COMPILER_IS_C11_COMPLIANT + template using filter_t = typename filter_t_tr::type; +#endif + +/** + * filter_out(t) : + * Given a tuple t, and integers, returns the tuple where the elements at initial position I are dropped. + */ + + // pos = position in the tuple, c : counter tuplesize-1 ->0, I : position to filter + template struct filter_out_impl; + + // default case where pos != the first I : increase pos + template struct filter_out_impl : filter_out_impl {}; + + // when pos == first I + template struct filter_out_impl { + template auto operator() (TupleIn const & t, TupleOut && out) const + DECL_AND_RETURN( filter_out_impl ()( t, push_back(std::forward(out),std::get(t)))); + }; + + template struct filter_out_impl { + template TupleOut operator() (TupleIn const & t, TupleOut && out) const {return out;} + }; + + template + auto filter_out(Tu const & tu) DECL_AND_RETURN ( filter_out_impl<0,std::tuple_size::value-1, I...>()(tu, std::make_tuple())); + + template struct filter_out_t_tr : std::result_of< filter_out_impl<0,std::tuple_size::value-1, I...>( Tu, std::tuple<>)>{}; + +#ifdef TRIQS_COMPILER_IS_C11_COMPLIANT + template using filter_out_t = typename filter_out_t_tr::type; +#endif + + /** + * inverse_filter(t,x) + * Given a tuple t, and integers, returns the tuple R of size L such that filter(R) == t + * and the missing position are filled with object x. + * Precondition (static_assert : sizeof...(I)==size of t) + * and max (I) < L + */ + + // pos = position in the tuple, c : counter tuplesize-1 ->0, I : position to filter + template struct inverse_filter_impl; + + // default case where pos != the first I + template struct inverse_filter_impl { + template auto operator() (TupleIn const & t, TupleOut && out, X const & x) const + DECL_AND_RETURN( inverse_filter_impl ()( t, push_back(std::forward(out),std::get(t)),x)); + }; + + // when pos == first I + template struct inverse_filter_impl { + template auto operator() (TupleIn const & t, TupleOut && out, X const & x) const + DECL_AND_RETURN( inverse_filter_impl ()( t, push_back(std::forward(out),x), x)); + }; + + template struct inverse_filter_impl { + template TupleOut operator() (TupleIn const &, TupleOut && out, X const &) const {return out;} + }; + + // put out for clearer error message + template< typename Tu, typename X, int L, int ...I> struct inverse_filter_r_type { + static_assert(sizeof...(I) == std::tuple_size::value, "inverse filter : the # of int must be equal to the tuple size !!"); + typedef inverse_filter_impl<0,0,L-1, I...> type; + }; + + template + auto inverse_filter(Tu const & tu, X const &x) DECL_AND_RETURN ( typename inverse_filter_r_type::type ()(tu, std::make_tuple(),x)); + + /** + * inverse_filter_out(t,x) + * Given a tuple t, and integers, returns the tuple R such that filter_out(R) == t + * and the missing position are filled with object x. + */ + + // pos = position in the tuple, c : counter tuplesize-1 ->0, I : position to filter + template struct inverse_filter_out_impl; + + // default case where pos != the first I + template struct inverse_filter_out_impl { + template auto operator() (TupleIn const & t, TupleOut && out, X const & x) const + DECL_AND_RETURN( inverse_filter_out_impl ()( t, push_back(std::forward(out),std::get(t)),x)); + }; + + // when pos == first I + template struct inverse_filter_out_impl { + template auto operator() (TupleIn const & t, TupleOut && out, X const & x) const + DECL_AND_RETURN( inverse_filter_out_impl ()( t, push_back(std::forward(out),x), x)); + }; + + template struct inverse_filter_out_impl { + template TupleOut operator() (TupleIn const &, TupleOut && out, X const &) const {return out;} + }; + + template + auto inverse_filter_out(Tu const & tu, X const &x) DECL_AND_RETURN ( inverse_filter_out_impl<0,0,std::tuple_size::value+sizeof...(I)-1, I...>()(tu, std::make_tuple(),x)); + + /** + * replace(t,r) + * Given a tuple t, and integers, returns the tuple where the elements at initial position I are replaced by r + */ + + // pos = position in the tuple, c : counter tuplesize-1 ->0, I : position to filter + template struct replace_impl; + + // default case where pos != the first I : increase pos + template struct replace_impl { + template auto operator() (TupleIn const & t, TupleOut && out, R const & r) const + DECL_AND_RETURN( replace_impl ()( t, push_back(std::forward(out),r),r)); + }; + + // when pos == first I + template struct replace_impl { + template auto operator() (TupleIn const & t, TupleOut && out, R const & r) const + DECL_AND_RETURN( replace_impl ()( t, push_back(std::forward(out),std::get(t)), r)); + }; + + template struct replace_impl { + template TupleOut operator() (TupleIn const & t, TupleOut && out, R const & r) const {return out;} + }; + + template + auto replace(Tu const & tu, R const &r) DECL_AND_RETURN ( replace_impl<0,std::tuple_size::value-1, I...>()(tu, std::make_tuple(),r)); + + /* * print a tuple */ @@ -285,5 +437,10 @@ namespace std { } } + + + + + #endif