functorN_expr.hpp 12.7 KB
Newer Older
1
2
3
4
5
6
7
/******************************************************************************
 *
 * AMDiS - Adaptive multidimensional simulations
 *
 * Copyright (C) 2013 Dresden University of Technology. All Rights Reserved.
 * Web: https://fusionforge.zih.tu-dresden.de/projects/amdis
 *
8
 * Authors:
9
10
11
12
13
14
15
16
17
 * Simon Vey, Thomas Witkowski, Andreas Naumann, Simon Praetorius, et al.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 *
 * This file is part of AMDiS
 *
 * See also license.opensource.txt in the distribution.
18
 *
19
20
21
22
23
24
25
26
27
28
29
30
 ******************************************************************************/



/** \file functorN_expr.h */

#ifndef AMDIS_FUNCTOR_N_EXPRESSION_HPP
#define AMDIS_FUNCTOR_N_EXPRESSION_HPP

#include "AMDiS_fwd.h"
#include "LazyOperatorTerm.h"
#include "Functors.h"
31
// #include "expressions/functor_expr.hpp"
32
33
34
35
36
#include "operations/functors.hpp"

#include <boost/static_assert.hpp>

#include <tuple>
37
#include <utility>
38
#include <functional>
39

40
namespace AMDiS
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
{
  /// for_each for std::tuple
  template<std::size_t I = 0, typename FuncT, typename... Tp>
  inline typename std::enable_if<I == sizeof...(Tp), void>::type
  for_each(std::tuple<Tp...> &, FuncT) { }

  template<std::size_t I = 0, typename FuncT, typename... Tp>
  inline typename std::enable_if<I < sizeof...(Tp), void>::type
  for_each(std::tuple<Tp...>& t, FuncT f)
  {
    f(std::get<I>(t));
    for_each<I + 1, FuncT, Tp...>(t, f);
  }

  template<int I>
  using int_ = std::integral_constant<int, I>;
57
58


59
60
61
62
63
64
65
66
67
  namespace traits
  {
    /// get the degree of a functor by combining the degrees of the arguments
    template<typename F, typename Enable = void>
    struct functor_degree
    {
      template<typename... Int>
      static int eval(F f, Int... d) { return 0; }
    };
68

69
    template<typename F>
70
    struct functor_degree<F, typename enable_if< boost::is_base_of<FunctorBase, F> >::type >
71
72
73
74
    {
      template<typename... Int>
      static int eval(F f, Int... d) { return f.getDegree(d...); }
    };
75

76
77
78
79
80
81
82
    // specialization for abstract-functions
    template<typename R, typename... Args>
    struct functor_degree<AbstractFunction<R, Args...> >
    {
      template<typename... Int>
      static int eval(AbstractFunction<R, Args...> const& fct, Int... d) { return fct.getDegree(); }
    };
83

84
85
86
87
88
89
    template<typename R, typename Arg0, typename Arg1>
    struct functor_degree<BinaryAbstractFunction<R, Arg0, Arg1> >
    {
      template<typename... Int>
      static int eval(BinaryAbstractFunction<R, Arg0, Arg1> const& fct, Int... d) { return fct.getDegree(); }
    };
90

91
92
93
94
95
96
    template<typename R, typename Arg0, typename Arg1, typename Arg2>
    struct functor_degree<TertiaryAbstractFunction<R, Arg0, Arg1, Arg2> >
    {
      template<typename... Int>
      static int eval(TertiaryAbstractFunction<R, Arg0, Arg1, Arg2> const& fct, Int... d) { return fct.getDegree(); }
    };
97

98
  } // end namespace traits
99

100
  namespace result_of
101
  {
102
103
    template<class T>
    struct void_{ typedef void type; };
104

105
106
107
108
109
110
111
    /// extract result type from function pointers
    template <class FPtr>
    struct Function;

    template <class R, class C, class... As>
    struct Function<R (C::*)(As...)>
    {
112
	    typedef R type;
113
114
115
116
117
    };

    template<class R, class C, class... As>
    struct Function<R (C::*)(As...) const>
    {
118
	    typedef R type;
119
    };
120

121
    template <class T>
122
123
124
    typename Function<T>::type function_helper(T);

    /// extract result type from functors
125
    template <class F, class Eanbled = void>
126
127
128
129
    struct Functor
    {
      typedef decltype(function_helper(&F::operator())) type;
    };
130

131
132
133
134
135
136

    template <class F>
    struct Functor<F, typename void_<typename F::value_type>::type>
    {
      typedef typename F::value_type type;
    };
137

138
139
140
141
142
    template <class F>
    struct Functor<F, typename void_<typename F::result_type>::type>
    {
      typedef typename F::result_type type;
    };
143
144


145
  } // end namespace result_of
146

147
148

  namespace detail
149
150
151
  {
    /// Functor that initializes the feSpace list
    template<typename List>
152
    struct InsertFeSpaces
153
154
155
    {
      List& feSpaces;
      InsertFeSpaces(List& feSpaces_) : feSpaces(feSpaces_) {};
156

157
158
159
160
161
      template<typename Term>
      void operator()(Term& term) {
	term.insertFeSpaces(feSpaces);
      }
    };
162

163
164
    /// Functor that is called on each term to initialize it on an element
    template<typename OT>
165
    struct InitElement
166
167
168
169
170
171
    {
      OT* ot;
      const ElInfo *elInfo, *elInfo2;
      SubAssembler* subAssembler;
      Quadrature *quad;
      const BasisFunction *basisFct;
172

173
174
175
      InitElement(OT* ot_, const ElInfo* elInfo_, SubAssembler* subAssembler_, Quadrature *quad_, const BasisFunction *basisFct_)
	: ot(ot_), elInfo(elInfo_), elInfo2(NULL), subAssembler(subAssembler_),
	  quad(quad_), basisFct(basisFct_) {}
176

177
178
179
      InitElement(OT* ot_, const ElInfo* smallElInfo_, const ElInfo* largeElInfo_, SubAssembler* subAssembler_, Quadrature *quad_,  const BasisFunction *basisFct_)
	: ot(ot_), elInfo(smallElInfo_), elInfo2(largeElInfo_), subAssembler(subAssembler_),
	  quad(quad_), basisFct(basisFct_) {}
180

181
182
183
184
185
186
187
188
      template<typename Term>
      void operator()(Term& term) {
	if (elInfo2)
	  term.initElement(ot, elInfo, elInfo2, subAssembler, quad, basisFct);
	else
	  term.initElement(ot, elInfo, subAssembler, quad, basisFct);
      }
    };
189

190
  } // end namespace detail
191

192
193

  /// Operator term with arbitrary number of sub-term (expressions)
194
  template <class... Terms>
195
196
197
  struct LazyOperatorTerms : public LazyOperatorTermBase
  {
    std::tuple<Terms...> term_tuple;
198

199
    LazyOperatorTerms(Terms const&... terms_)
200
      : term_tuple(terms_...)
201
    { }
202

203
    template <class List>
204
205
206
207
208
    inline void insertFeSpaces(List& feSpaces)
    {
      for_each(term_tuple, detail::InsertFeSpaces<List>(feSpaces));
    }

209
    template <class OT>
210
    inline void initElement(OT* ot, const ElInfo* elInfo,
211
		    SubAssembler* subAssembler, Quadrature *quad,
212
213
214
215
216
		    const BasisFunction *basisFct = NULL)
    {
      for_each(term_tuple, detail::InitElement<OT>(ot, elInfo, subAssembler, quad, basisFct));
    }

217
    template <class OT>
218
    inline void initElement(OT* ot, const ElInfo* smallElInfo, const ElInfo* largeElInfo,
219
		    SubAssembler* subAssembler, Quadrature *quad,
220
221
222
223
		    const BasisFunction *basisFct = NULL)
    {
      for_each(term_tuple, detail::InitElement<OT>(ot, smallElInfo, largeElInfo, subAssembler, quad, basisFct));
    }
224

225
226
227
    inline double operator()(const int& iq) const;
  };

228

229
230
231
  // the expressions
  // _____________________________________________________________________________

232
  namespace expressions
233
234
  {
    /// Functor that takes arbitrary number of arguments
235
    template <class F, class... Terms>
236
237
238
239
    struct FunctionN : public LazyOperatorTerms<Terms...>
    {
      typedef LazyOperatorTerms<Terms...> super;
      static const int N = sizeof...(Terms);
240

241
      typedef typename result_of::Functor<F>::type value_type;
242
      BOOST_STATIC_ASSERT_MSG( (!boost::is_same<value_type, traits::no_valid_type>::value), "********** ERROR: You have to define a result_type for your Functor **********" );
243

244
      F f; ///< the functor
245

246
      FunctionN(F const& f_, Terms const&... terms_)
247
	: super(terms_...), f(f_) {}
248
249

      // call f.getDegree() function
250
251
      template<int I, class... Terms_>
      int getDegree(int_<I>, Terms_&&... terms) const
252
      {
253
	return getDegree(int_<I-1>(), std::get<I-1>(super::term_tuple), std::forward<Terms_>(terms)...);
254
      }
255

256
257
      template <class... Terms_>
      int getDegree(int_<0>, Terms_&&... terms) const
258
259
260
      {
	return traits::functor_degree<F>::eval(f, terms.getDegree()...);
      }
261

262
263
264
265
266
267
      int getDegree() const
      {
	return getDegree(int_<N>());
      }

      // call f.operator()(...)
268
269
      template <int I, class... Terms_>
      inline value_type eval(const int& iq, int_<I>, Terms_&&... terms) const
270
      {
271
	return eval(iq, int_<I-1>(), std::get<I-1>(super::term_tuple), std::forward<Terms_>(terms)...);
272
      }
273

274
275
      template <class... Terms_>
      inline value_type eval(const int& iq, int_<0>, Terms_&&... terms) const
276
277
278
      {
	return f(terms(iq)...);  // f(term1(iq), term2(iq), term3(iq),...)
      }
279

280
      inline value_type operator()(const int& iq) const { return eval(iq, int_<N>()); }
281

Praetorius, Simon's avatar
Praetorius, Simon committed
282
283
284
285
286
      template <int I>
      std::string str(int_<I>) const
      {
	return str(int_<I-1>()) + ", " + std::get<I>(super::term_tuple).str();
      }
287

Praetorius, Simon's avatar
Praetorius, Simon committed
288
289
290
291
      std::string str(int_<0>) const
      {
	return std::get<0>(super::term_tuple).str();
      }
292

Praetorius, Simon's avatar
Praetorius, Simon committed
293
      std::string str() const { return std::string("F(") + str(int_<N-1>()) + ")"; }
294
    };
295

296
297
    template<typename F, typename Term>
    using Function1 = FunctionN<F, Term>;
298

299
300
    template<typename F, typename Term1, typename Term2>
    using Function2 = FunctionN<F, Term1, Term2>;
301

302
303
    template<typename F, typename Term1, typename Term2, typename Term3>
    using Function3 = FunctionN<F, Term1, Term2, Term3>;
304

305
306
    template<typename F, typename Term1, typename Term2, typename Term3, typename Term4>
    using Function4 = FunctionN<F, Term1, Term2, Term3, Term4>;
307
308


309
    /// A wrapper functor for AMDiS::AbstractFunctions
310
    template <class TOut, class TIn>
311
312
313
314
315
    struct Wrapper : public FunctorBase
    {
      typedef TOut result_type;
      Wrapper(AbstractFunction<TOut, TIn>* fct_) : fct(fct_) {}
      int getDegree(int degree) const { return fct->getDegree(); }
316
317

      TOut operator()(const TIn& x) const
318
319
320
      {
	return (*fct)(x);
      }
321

322
323
324
    protected:
      AbstractFunction<TOut, TIn>* fct;
    };
325
326


327
328
329
330
    template <int D, class F>
    struct DegreeWrapper : public FunctorBase
    {
      typedef typename result_of::Functor<F>::type result_type;
331
332
333

      DegreeWrapper(F const& fct_) : fct(fct_) {}

334
335
      template <class... Int>
      int getDegree(Int... degrees) const { return D; }
336

337
      template <class... Ts>
338
      result_type operator()(Ts&&... args) const
339
      {
340
	return fct(std::forward<Ts>(args)...);
341
      }
342

343
344
345
    protected:
      F fct;
    };
346
347


348
349
    template <class F, class DegF>
    struct DegreeWrapper2 : public FunctorBase
350
    {
351
      typedef typename result_of::Functor<F>::type result_type;
352
353

      DegreeWrapper2(F const& fct_, DegF const& degfct_)
354
	: fct(fct_), degfct(degfct_) {}
355

356
      template <class... Int>
357
358
359
      int getDegree(Int... degrees) const
      {
	return degfct(degrees...);
360
      }
361

362
      template <class... Ts>
363
      result_type operator()(Ts&&... args) const
364
      {
365
	return fct(std::forward<Ts>(args)...);
366
      }
367

368
369
370
371
    protected:
      F fct;
      DegF degfct;
    };
372

373
374
375
376
377
378
  } // end namespace expressions


  namespace result_of
  {
    // result of generator-functions (used for enable_if constructs)
379
380
    template <typename F, typename... Terms>
    struct FunctionN : std::enable_if
381
      <
382
	and_< typename traits::is_valid_arg<Terms>::type... >::value,
383
	expressions::FunctionN< F, typename traits::to_expr<Terms>::type...>
384
      > {};
385

386
387
388
389
    template <typename F, typename Term>
    struct FunctionN<F, Term> : std::enable_if
      <
	traits::is_valid_arg<Term>::value,
390
	expressions::FunctionN< F, typename traits::to_expr<Term>::type>
391
      > {};
392

393
394
395
396
397
398
399
  } // end namespace result_of

  // generator-functions
  // _____________________________________________________________________________

  template<typename F, typename... Terms>
  inline typename result_of::FunctionN<F, Terms...>::type
400
  function_(F const& f, Terms const&... ts)
401
402
  {
    return expressions::FunctionN<F, typename traits::to_expr<Terms>::to::type...>
403
	    (f, traits::to_expr<Terms>::to::get(ts)...);
404
405
406
407
  }

  template<typename F, typename... Terms>
  inline typename result_of::FunctionN<F, Terms...>::type
408
  func(F const& f, Terms const&... ts)
409
410
  {
    return expressions::FunctionN<F, typename traits::to_expr<Terms>::to::type...>
411
	    (f, traits::to_expr<Terms>::to::get(ts)...);
412
413
414
415
  }

  template<typename F, typename Term0, typename... Terms>
  inline typename result_of::FunctionN<F, Term0, Terms...>::type
416
  eval(F const& f, Term0 t0, Terms const&... ts)
417
  {
418
    return expressions::FunctionN<F, typename traits::to_expr<Term0>::to::type,
419
				     typename traits::to_expr<Terms>::to::type...>
420
      (f, traits::to_expr<Term0>::to::get(t0), traits::to_expr<Terms>::to::get(ts)...);
421
422
  }

423
424
425
426

  // function wrapper for abstract functions
  // _____________________________________________________________________________
  template<typename TOut, typename TIn>
427
  inline expressions::Wrapper<TOut,TIn> wrap(AbstractFunction<TOut, TIn>* fct)
428
429
  { return expressions::Wrapper<TOut,TIn>(fct); }

430
431
  template <int Degree, class F>
  inline expressions::DegreeWrapper<Degree, F>
432
  deg(F const& fct)
433
  {
434
    return expressions::DegreeWrapper<Degree, F>(fct);
435
  }
436

437
438
  template <class F, class DegF>
  inline expressions::DegreeWrapper2<F, DegF>
439
  deg(F const& fct, DegF const& degfct)
440
  {
441
    return expressions::DegreeWrapper2<F, DegF>(fct, degfct);
442
  }
443

444
445
446
} // end namespace AMDiS

#endif // AMDIS_FUNCTOR_N_EXPRESSION_HPP