Composer.hpp 2.96 KB
Newer Older
1 2 3 4 5 6 7
#pragma once

#include <tuple>
#include <type_traits>

#include <dune/common/std/apply.hh>

8
#include <amdis/common/Concepts.hpp>
9 10
#include <amdis/common/Mpl.hpp>
#include <amdis/operations/Basic.hpp>
11 12 13 14 15

namespace AMDiS
{
  namespace Operation
  {
16 17 18 19 20 21 22 23 24 25 26 27 28
	    /// \brief Composition of Functors.
	    /**
	     * \ingroup operations
	     * Implement the composition `c:=f(g1,g2,...,gN), where `f` is an N-ary functor
	     * `gI` are functors of the same arity. The composition is defined as
	     * ```
	     * c(a1,a2,...,aM) := f(g1(a1,a2,..,aM), g2(a1,a2,...,aM),...,gN(a1,a2,...,aM))
	     * ```
	     *
	     * **Requirements:**
	     * - sizeof...(Gs) == N, with N = arity(F)
	     * - arity(Gs[0]) == arity(Gs[i]) for i = 1,...,N-1
	     **/
29 30 31
    template <class F, class... Gs>
    struct Composer
    {
32 33
      template <class F_, class... Gs_,
        REQUIRES( Concepts::Similar<Types<F,Gs...>, Types<F_,Gs_...>>) >
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
      constexpr Composer(F_&& f, Gs_&&... gs)
        : f_(std::forward<F_>(f))
        , gs_(std::forward<Gs_>(gs)...)
      {}

      template <class... Ts>
      constexpr auto operator()(Ts const&... args) const
      {
        auto eval = [&](auto const& g) { return g(args...); };
        return Dune::Std::apply([&,this](auto const&... gs) { return f_(eval(gs)...); }, gs_);
      }

      F f_;
      std::tuple<Gs...> gs_;
    };

50
#ifndef DOXYGEN
51 52 53 54 55 56 57 58 59 60 61
    template <class F, class... Gs>
    struct ComposerBuilder
    {
      using type = Composer<F, Gs...>;

      template <class F_, class... Gs_>
      static constexpr type build(F_&& f, Gs_&&... gs)
      {
        return type{std::forward<F_>(f), std::forward<Gs_>(gs)...};
      }
    };
62
#endif
63

64
    /// Generator function for \ref Composer
65
    template <class F, class... Gs>
66
    constexpr auto compose(F&& f, Gs&&... gs)
67 68 69 70 71 72
    {
      return ComposerBuilder<std::decay_t<F>, std::decay_t<Gs>...>::build(
        std::forward<F>(f), std::forward<Gs>(gs)...);
    }

    // Polynomial order or composed function combines the orders of the sub-functions
73 74 75
    template <class F, class... Gs, class... Int,
      REQUIRES(Concepts::HasFunctorOrder<F,sizeof...(Gs)>
               && all_of_v<Concepts::HasFunctorOrder<Gs,sizeof...(Int)>...>)>
76 77 78 79 80 81 82 83 84
    int order(Composer<F,Gs...> const& c, Int... degrees)
    {
      auto deg = [&](auto const& g) { return order(g, int(degrees)...); };
      return Dune::Std::apply([&](auto const&... gs) { return order(c.f_, deg(gs)...); }, c.gs_);
    }

    /// Partial derivative of composed function:
    /// Implements: // sum_i [ d_i(f)[g...] * d_j(g_i) ]
    template <int J, class F, class... Gs>
85
    auto partial(Composer<F,Gs...> const& c, index_t<J> _j);
86 87


88
#ifndef DOXYGEN
89 90 91 92 93 94 95 96 97 98 99 100 101 102
    // some specialization for the composer

    // id(g) => g
    template <class F>
    struct ComposerBuilder<Id, F>
    {
      using type = F;

      template <class F_>
      static constexpr F build(F_&& f)
      {
        return F{std::forward<F_>(f)};
      }
    };
103
#endif
104 105 106

  } // end namespace Operation
} // end namespace AMDiS