2. Tuple tools
Various standard functional operations on tuple.
2.1. apply
Purpose: apply a function on a tuple of arguments
Given a function object f, and its arguments stored in a tuple t, and we want to apply f on t.
Python equivalent:
def apply(f,t): return f(*t)
Synopsis
template<typename Function, typename Tuple> auto apply (Function && f, Tuple const & t);
Example :
#include <triqs/utility/tuple_tools.hpp>
#include <iostream>
int main() {
auto fun = [](int i, double x, double y, int k) { return 6 * k + i - 1.3 * x + 2 * y; };
auto t = std::make_tuple(1, 2.3, 4.3, 8);
auto res = triqs::tuple::apply(fun, t);
std::cout << " f(t) =" << res << std::endl;
}
2.2. for_each
Purpose: apply a function for each element of a tuple (in order)
Given a function object f, we want to apply it to all elements of a tuple t.
Python equivalent:
def for_each(t,f): for x in t: f(x)
Synopsis
template<typename Function, typename Tuple> void for_each(Tuple const & t, Function && f);
Example :
#include <triqs/utility/tuple_tools.hpp>
#include <iostream>
int main() {
auto t = std::make_tuple(1, 2.3, 4.3, 8);
auto l = [](double x) { std::cout << x << " "; };
triqs::tuple::for_each(t, l);
}
2.3. for_each_zip
Purpose: apply a function for each element of tuple zip (in order)
Python equivalent:
def for_each(f,t0,t1): for x0,x1 in itertools.zip(t0,t1): f(x0,x1)
Synopsis
template <typename F, typename T0, typename T1> void for_each_zip(F &&f, T0 &&t0, T1 &&t1);
template <typename F, typename T0, typename T1, typename T2> void for_each_zip(F &&f, T0 &&t0, T1 &&t1, T2 &&t2);
Example :
#include <triqs/utility/tuple_tools.hpp>
#include <iostream>
int main() {
auto t1 = std::make_tuple(1, 2.3, 4.3, 8);
auto t2 = std::make_tuple('|', '|', '|', '|');
auto l = [](double x, char c) { std::cout << c << " " << x << " "; };
triqs::tuple::for_each_zip(l, t1, t2);
}
2.4. map
Purpose: map a function on a tuple to create a new tuple
Python equivalent:
def map(f,t): return (f(x) for x in t)
Synopsis
template <typename T, typename F> auto map(F &&f, T &&t);
Returns:
The result is a tuple, of the same length as T, made of the evaluation of f on the elements on T
Example :
#include <triqs/utility/tuple_tools.hpp>
#include <iostream>
int main() {
auto t = std::make_tuple(1, 2.3, 4.3, 8);
auto l = [](double x) { return -x; };
auto res = triqs::tuple::map(l, t);
std::cout << res << std::endl;
}
2.5. fold
Purpose: reduction of a tuple with a function
Python equivalent:
def fold(f,t,r): return reduce(f,t,r)
Synopsis
(1) template <typename F, typename T, typename R>
decltype(auto) fold(F &&f, T &&t, R &&r);
(2) template <typename F, typename T0, typename T1, typename R>
decltype(auto) fold(F &&f, T0 &&t0, T1 &&t1, R &&r);
Returns:
f(get<N>(t),
f(get<N-1>(t),
...,
f(get<0>(t),r))) (1)
f(get<N>(t0), get<N>(t1),
f(get<N-1>(t0), get<N-1>(t1),
...,
f(get<0>(t0), get<0>(t1), r))) (2)
Parameters :
f: a callable object of signature
f(x, r) -> r' (1) f(x, y, r) -> r' (2)The return type of f must be a valid last parameter for f (at least for one overload).
t: a tuple
t0,t1: two tuples of the same size
r: anything that can be a last parameter for f.
Precondition: everything so that the resulting expression is valid (in particular, f must be called on each tuple elements, with its return type as last parameter.
Warning
The type of the result is not necessarly R: it is automatically deduced from this expression. Cf example.
Example :
#include <triqs/utility/tuple_tools.hpp>
#include <iostream>
int main() {
auto t = std::make_tuple(1, 2.3, 4.3, 8);
// a simple example : make a sum
auto f = [](double x, double r) { return x + r; };
auto res = triqs::tuple::fold(f, t, 0); // <-- R is int but res is a double (from f's return type).
std::cout << res << std::endl;
// the types of x and r may be different
triqs::tuple::fold([](double x, std::ostream &os) -> std::ostream & { return os << "|" << x; }, t, std::cout);
// example with zip
auto t0 = std::make_tuple(1, 2, 3, 4);
auto t1 = std::make_tuple(1, -1, 1, -1);
auto res2 = triqs::tuple::fold([](double x, double y, double r) { return y * x + r; }, t0, t1, 0);
std::cout << "\n " << res2 << std::endl;
}
2.6. reverse
Purpose: lazy reverse of a tuple
Python equivalent: None.
Synopsis
namespace std {
template<typename ... T> TU reverse(std::tuple<T...> && x);
template<typename ... T> TU reverse(std::tuple<T...> & x);
template<typename ... T> TU reverse(std::tuple<T...> const& x);
}
Warning
reverse is declared in std:: to benefit from ADL (a bit dangerous, but ok here).
Returns:
TU is a tuple like type, that :
Contains a ref of the original tuple, or the tuple if a && was passed.
Hence, no copy is ever made.
Accepts std::get and std::tuple_size, like tuple.
reverse(t) can therefore be used in place of a regular tuple in the algorithms of this section.
Example :
#include <triqs/utility/tuple_tools.hpp>
#include <iostream>
int main() {
auto t = std::make_tuple(1, 2.3, 4.3, 8);
auto l = [](double x) { std::cout << x << " "; };
triqs::tuple::for_each(t, l);
std::cout << std::endl;
triqs::tuple::for_each(reverse(t), l);
}
2.7. called_on_tuple
Purpose: Adapting a function to call with a tuple argument and flatten it
Python equivalent:
def called_on_tuple(f): return lambda x: f(*x)
Synopsis
template <typename F> F2 called_on_tuple(F &&f);
Returns:
F2 is a function object which adapts the function f for calling on a tuple.
The following call are therefore equivalent:
called_on_tuple(f)( std::tie(x0,x1,x2)) f(x0,x1,x2)
Example :
#include <triqs/utility/tuple_tools.hpp>
#include <iostream>
int main() {
auto fun = [](int i, double x, double y, int k) { return 6 * k + i - 1.3 * x + 2 * y; };
auto t = std::make_tuple(1, 2.3, 4.3, 8);
auto res = triqs::tuple::called_on_tuple(fun)(t);
std::cout << " f(t) =" << res << std::endl;
}
f(t) =54.61
Implementation :
The C++ is simple in fact
template <typename F> struct _called_on_tuple { F _f; template <typename Tu> decltype(auto) operator()(Tu &&tu) { return apply(_f, std::forward<Tu>(tu)); } }; template <typename F> _called_on_tuple<F> called_on_tuple(F &&f) { return {std::forward<F>(f)}; }