22

I am currently coding some cryptographic algorithms in C++11 that require a lot of function compositions. There are 2 types of composition I have to deal with :

  1. Compose a function on itself a variable number of times. Mathematically, for a certain function F, F^n(x) = (F^{n-1} o F)(x) = F^{n-1}(F(x)).

  2. Compose different functions together. For example, for some functions f,g,h,i,j and k of the same type, I'll have f(g(h(i(j(k(x)))))).

In my case, I'm using the following definition of F :

const std::vector<uint8_t> F(const std::vector<uint8_t> &x);

I would like to compose this function on itself n times. I have implemented the composition in a simple recursive way which is working fine :

const std::vector<uint8_t> compose(const uint8_t n, const std::vector<uint8_t> &x)
{
    if(n > 1)
       return compose(n-1, F(x));

    return F(x);
}

For this case, is there a more efficient way an proper way to implement this composition using c++11 but without using BOOST ? It would be great to use this form if it is possible of course :

answer = compose<4>(F)(x); // Same as 'answer = F^4(x) = F(F(F(F(x))))'

For the second case, I would like to implement the composition of a variable number of functions. For a given set of functions F0, F1, ..., Fn having the same definition as F, is there an efficient and proper way to compose them where n is variable ? I think variadic template would be useful here, but I don't know how to use them in that case.

Thanks for your help.

Gabriel L.
  • 4,678
  • 5
  • 25
  • 34
  • If you use the STL, you may use `unary_compose` (and peek at its implementation). – BatchyX Sep 28 '13 at 20:30
  • It is possible that your compiler already [optimizes the tail-recursion](http://stackoverflow.com/q/34125/420683). – dyp Sep 28 '13 at 20:41
  • 2
    *Side remark*: The signature of `F` necessitates creating a new vector (which can only be elided if the compiler inlines `F`). It typically is not a good idea to return a `const` object, because it prohibits move semantics. With a signature like `std::vector F(std::vector)` (sic, pass-by-value), you could leverage move elision and possibly work on the same vector with all `F`s, keeping the "immutable" semantics. – dyp Sep 28 '13 at 20:55
  • Do you want to store the composed function or just run it? – dyp Sep 28 '13 at 21:32
  • @DyP You mentioned a good point there. The move semantics avoid unnecessary copies and will make my code more efficient, because I use **a lot of vectors**. Thanks for the remark. About your question, I store the result of the composed function in a vector like the following example : `std::vector result = compose(4, x);` where compose is the recursive function I used in my post. – Gabriel L. Sep 29 '13 at 12:25

7 Answers7

17

Something along these lines, perhaps (untested):

template <typename F>
class Composer {
  int n_;
  F f_;
public:
  Composer(int n, F f) : n_(n), f_(f) {}

  template <typename T>
  T operator()(T x) const {
    int n = n_;
    while (n--) {
      x = f_(x);
    }
    return x;
  }
};

template <int N, typename F>
Composer<F> compose(F f) {
  return Composer<F>(N, f);
}

EDIT: And for the second case (tested this time):

#include <iostream>

template <typename F0, typename... F>
class Composer2 {
    F0 f0_;
    Composer2<F...> tail_;
public:
    Composer2(F0 f0, F... f) : f0_(f0), tail_(f...) {}

    template <typename T>
    T operator() (const T& x) const {
        return f0_(tail_(x));
    }
};

template <typename F>
class Composer2<F> {
    F f_;
public:
    Composer2(F f) : f_(f) {}

    template <typename T>
    T operator() (const T& x) const {
        return f_(x);
    }
};

template <typename... F>
Composer2<F...> compose2(F... f) {
    return Composer2<F...>(f...);
}

int f(int x) { return x + 1; }
int g(int x) { return x * 2; }
int h(int x) { return x - 1; }

int main() {
  std::cout << compose2(f, g, h)(42);
  return 0;
}
Igor Tandetnik
  • 50,461
  • 4
  • 56
  • 85
  • Your code works fine with non-member functions. What if the function F I specified in my post is a non-static member of a class Foo ? I tried with std::bind as the following example : `A = compose2<4>(std::bind(&Foo::F, this, std::placeholders::_1))(A)` but I get a compiler error : `error: no match for ‘operator=’ in ‘x = std::_Bind<_Functor(_Bound_args ...)>::operator()(_Args&& ...) const ...`. – Gabriel L. Sep 29 '13 at 14:28
  • My `compose2` doesn't take an integer as its template parameter. If you meant `compose`, then it [works for me](http://ideone.com/tQJ3xD). – Igor Tandetnik Sep 29 '13 at 16:01
  • Nice. Using trailing return type in operator() would allow to relax type constraints and compose in a more freely way. – ubik Nov 02 '15 at 16:48
  • 1
    IMO, it would be better if you changed the signature of `operator()` of composer to return `auto` or `decltype(auto)` (needs C++14), so that you can chain functions that take an argument of type T and return a value of different type. See at http://ideone.com/5z2hTw for demo. – Marek Kurdej Apr 19 '17 at 13:04
12

Thanks for the fun question, Gabriel of year 2013. Here is a solution. It works in c++14.

#include <functional>
#include <iostream>
using std::function;

// binary function composition for arbitrary types
template <class F, class G> auto compose(F f, G g) {
  return [f, g](auto x) { return f(g(x)); };
}

// for convienience
template <class F, class G> auto operator*(F f, G g) { return compose(f, g); }

// composition for n arguments
template <class F, typename... Fs> auto compose(F f, Fs &&... fs) {
  return f * compose(fs...);
}

// composition for n copies of f
template <int i, class F>
// must wrap chain in a struct to allow partial template specialization
struct multi {
  static F chain(F f) { return f * multi<i - 1, F>::chain(f); }
};
template <class F> struct multi<2, F> {
  static F chain(F f) { return f * f; }
};
template <int i, class F> F compose(F f) { return multi<i, F>::chain(f); }

int main(int argc, char const *argv[]) {

  function<double(int)> f = [](auto i) { return i + 3; };
  function<int(double)> g = [](auto i) { return i * 2; };
  function<int(int)> h = [](auto i) { return i + 1; };

  std::cout << '\n'
            << "9   == " << compose(f, g, f)(0) << '\n'
            << "5   == " << (f * g * h)(0) << '\n'
            << "100 == " << compose<100>(h)(0) << '\n';

  return 0;
}

You can define

Matrix compose(Matrix f, Matrix g);

or

Rotation compose(Rotation f, Rotation g);

to reuse this code for all sorts of things.

bddap
  • 529
  • 4
  • 8
2

A very general example (g++ -std=c++1y composition.cpp):

// ---------------------------------------------------------
// "test" part
// ---------------------------------------------------------
int f(int a) { return 2*a; }
double g(int a) { return a+2.5; }
double h(double a) { return 2.5*a; }
double i(double a) { return 2.5-a; }

class Functor {
  double x;
public:
  Functor (double x_) :  x(x_) { }
  double operator() (double a) { return a*x; }
};

// ---------------------------------------------------------
// ---------------------------------------------------------
int main () {

  auto l1 = [] (double a) { return a/3; };
  auto l2 = [] (double a) { return 3.5+a; };

  Functor fu {4.5};

  auto compos1 = compose (f, g, l1, g, h, h, l1, l2); 

  auto compos2 = compose (compos1, l1, l2, fu);

  auto x = compos2 (3);

  cout << x << endl;
  cout << compos2(3) << endl;

  cout << fu(l2(l1(l2(l1(h(h(g(l1(g(f(3))))))))))) << endl;

} // ()

Library part:

// ---------------------------------------------------------
// "library" part
// ---------------------------------------------------------
template<typename F1, typename F2>
class Composite{
private:
  F1  f1;
  F2  f2;

public:
  Composite(F1  f1,  F2  f2) : f1(f1), f2(f2) { }

  template<typename IN>
  decltype(auto) operator() (IN i)   
  { 
    return f2 ( f1(i) ); 
  }
};

// ---------------------------------------------------------
// ---------------------------------------------------------
template<typename F1, typename F2>
decltype(auto) compose (F1 f, F2 g) {
  return Composite<F1, F2> {f,g};
}

// ---------------------------------------------------------
// ---------------------------------------------------------
template<typename F1, typename... Fs>
decltype(auto) compose (F1  f,  Fs  ... args) 
{
  return compose (f, compose(args...));
}

The whole program:

//  g++ -std=c++1y composition.cpp 

#include <iostream>

using namespace std;

// ---------------------------------------------------------
// "library" part
// ---------------------------------------------------------
template<typename F1, typename F2>
class Composite{
private:
  F1  f1;
  F2  f2;

public:
  Composite(F1  f1,  F2  f2) : f1(f1), f2(f2) { }

  template<typename IN>
  decltype(auto) operator() (IN i)   
  { 
    return f2 ( f1(i) ); 
  }
};

// ---------------------------------------------------------
// ---------------------------------------------------------
template<typename F1, typename F2>
decltype(auto) compose (F1 f, F2 g) {
  return Composite<F1, F2> {f,g};
}

// ---------------------------------------------------------
// ---------------------------------------------------------
template<typename F1, typename... Fs>
decltype(auto) compose (F1  f,  Fs  ... args) 
{
  return compose (f, compose(args...));
}

// ---------------------------------------------------------
// "test" part
// ---------------------------------------------------------
int f(int a) { return 2*a; }
double g(int a) { return a+2.5; }
double h(double a) { return 2.5*a; }
double i(double a) { return 2.5-a; }

class Functor {
  double x;
public:
  Functor (double x_) :  x(x_) { }
  double operator() (double a) { return a*x; }
};

// ---------------------------------------------------------
// ---------------------------------------------------------
int main () {

  auto l1 = [] (double a) { return a/3; };
  auto l2 = [] (double a) { return 3.5+a; };

  Functor fu {4.5};

  auto compos1 = compose (f, g, l1, g, h, h, l1, l2); 

  auto compos2 = compose (compos1, l1, l2, fu);

  auto x = compos2 (3);

  cout << x << endl;
  cout << compos2(3) << endl;

  cout << fu(l2(l1(l2(l1(h(h(g(l1(g(f(3))))))))))) << endl;

} // ()
cibercitizen1
  • 20,944
  • 16
  • 72
  • 95
  • @dyp I tried decltype(auto) but it didn't compile. Maybe that was too much for the type deduction system. I'll be further investigating that. – cibercitizen1 Jan 01 '15 at 09:50
2

Here is a simple c++14 solution (it may probably be re-written to c++11):

#include <iostream>

// base condition
template <typename F>
auto compose(F&& f)
{
    return [a = std::move(f)](auto&&... args){
        return a(std::move(args)...);
    };
}

// recursive composition
// from compose(a, b, c...) to compose(ab, c...)
template <typename F1, typename F2, typename... Fs>
auto compose(F1&& f1, F2&& f2, Fs&&... fs)
{
    return compose(
        [first = std::move(f1), second = std::move(f2)]
        (auto&&... args){
            return second(first(std::move(args)...));
        },
        std::move(fs)...
    );
}

Possible usage:

int main()
{
const auto f = compose(
  [](const auto n){return n * n;},
  [](const auto n){return n + 2;},
  [](const auto n){return n + 2;}
);
std::cout << f(10) << std::endl; // outputs 104
}

Here is a link to the repo with a few more examples: https://github.com/nestoroprysk/FunctionComposition

Nestor
  • 687
  • 5
  • 12
1

A quick implementation of function iteration with argument forwarding. The helper type is unfortunately necessary because function templates can’t be partially specialised.

#include <functional>
#include <iostream>
using namespace std;

template<int n, typename A>
struct iterate_helper {
  function<A(A)> f;
  iterate_helper(function<A(A)> f) : f(f) {}
  A operator()(A&& x) {
    return f(iterate_helper<n - 1, A>(f)(forward<A>(x)));
  };
};

template<typename A>
struct iterate_helper<1, A> {
  function<A(A)> f;
  iterate_helper(function<A(A)> f) : f(f) {}
  A operator()(A&& x) {
    return f(forward<A>(x));
  };
};

template<int n, typename A>
function<A(A)> iterate(function<A(A)> f) {
  return iterate_helper<n, A>(f);
}

int succ(int x) {
  return x + 1;
}

int main() {
  auto add5 = iterate<5>(function<int(int)>(succ));
  cout << add5(10) << '\n';
}
Jon Purdy
  • 53,300
  • 8
  • 96
  • 166
  • 2
    If you're already writing templates, why not use a generic function argument instead of the type-erasing `std::function`? – dyp Sep 28 '13 at 20:38
  • @DyP: This implementation is just the first/simplest thing that came to mind, but you’re right that it could be deduced instead. Also, this only works with compile-time *n*, which Gabriel implied but didn’t specify. – Jon Purdy Sep 28 '13 at 20:42
  • 2
    One example of the `integral_constant` trick can be found at the end of [this answer](http://stackoverflow.com/a/16443823/420683). Using `std::function` instead of a template parameter makes it harder for the compiler/optimizer to get rid of the additional levels of indirection and heap allocation (though it can reduce code bloat..). – dyp Sep 28 '13 at 20:47
  • 1
    I second @DyP's comments about having the function's type as the template parameter instead of the argument/result type. You should consider editing your answer. – Geoff Reedy Sep 29 '13 at 05:18
0

You haven't shown the body of F, but if you can modify it so that it mutates the input to form the output then change the signature to:

void F(std::vector<uint8_t>& x);

Thereafter you can implement Fn as:

void Fn(std::vector<uint8_t>& x, size_t n)
{
    for (size_t i = 0; i < n; i++)
        F(x);
}

The compiler will unroll the loop for you if it is more efficient, but even if it doesn't an increment/compare of a local variable will be orders of magnitude faster than calling F.

You can then explcitly copy-construct new vectors when you actually want to make a copy:

vector<uint8_t> v1 = ...;
vector<uint8_t> v2 = v1; // explicitly take copy
Fn(v2,10);
Andrew Tomazos
  • 66,139
  • 40
  • 186
  • 319
0

What about (untested):

template < typename Func, typename T >
T  compose_impl( Func &&, T &&x, std::integral_constant<std::size_t, 0> )
{ return std::forward<T>(x); }

template < typename Func, typename T, std::size_t N >
T compose_impl( Func &&f, T &&x, std::integral_constant<std::size_t, N> )
{
    return compose_impl( std::forward<Func>(f),
     std::forward<Func>(f)(std::forward<T>( x )),
     std::integral_constant<std::size_t, N-1>{} );
}

template < std::size_t Repeat = 1, typename Func, typename T >
T  compose( Func &&f, T &&x )
{
    return compose_impl( std::forward<Func>(f), std::forward<T>(x),
     std::integral_constant<std::size_t, Repeat>{} );
}

We can use variadic function templates for multiple functions (untested):

template < typename Func, typename T >
constexpr  // C++14 only, due to std::forward not being constexpr in C++11
auto chain_compose( Func &&f, T &&x )
 noexcept( noexcept(std::forward<Func>( f )( std::forward<T>(x) )) )
 -> decltype( std::forward<Func>(f)(std::forward<T>( x )) )
{ return std::forward<Func>(f)(std::forward<T>( x )); }

template < typename Func1, typename Func2, typename Func3, typename ...RestAndT >
constexpr  // C++14 only, due to std::forward
auto  chain_compose( Func1 &&f, Func2 &&g, Func3 &&h, RestAndT &&...i_and_x )
 noexcept( CanAutoWorkHereOtherwiseDoItYourself )
 -> decltype( auto )  // C++14 only
{
    return chain_compose( std::forward<Func1>(f),
     chain_compose(std::forward<Func2>( g ), std::forward<Func3>( h ),
     std::forward<RestAndT>( i_and_x )...) );
}

The upcoming decltype(auto) construct automatically computes the return type from an inlined function. I don't know if there's a similar automatic computation for noexcept

CTMacUser
  • 1,996
  • 1
  • 16
  • 27