simplify_expr.hpp 20.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
31
32
33
 ******************************************************************************/



/** \file simplify_expr.hpp */

#ifndef AMDIS_SIMPLIFY_EXPRESSION_HPP
#define AMDIS_SIMPLIFY_EXPRESSION_HPP

#include "AMDiS_fwd.h"
#include "LazyOperatorTerm.h"
#include "value_expr.hpp"

#define SINGLE_ARG(...) __VA_ARGS__

34
namespace AMDiS
35
{
36
  namespace traits
37
38
39
  {
    template<typename T>
    struct is_ct_value : boost::mpl::false_ {};
40

41
42
    template<int I>
    struct is_ct_value< expressions::CValue<I> > : boost::mpl::true_ {};
43

44
  } // end namespace traits
45
46
47


  namespace expressions
48
  {
49
    template<typename Term>
50
51
52
53
    struct Simplify
    {
      typedef Term type;

54
55
      static type eval(Term const& t) { return t; }
    }; // by default do not simplify a term
56

57
  } // end namespace expressions
58

59
60

  // generator function for simplification
61
62
  template<typename Term>
  inline typename expressions::Simplify<Term>::type simplify(const Term& t)
63
64
65
  { return expressions::Simplify<Term>::eval(t); }


66
  namespace expressions
67
68
69
  {
    /// -(N) -> (-N)
    template<int N>
70
71
72
73
    struct Simplify< Negative<CValue<N> > >
    {
      typedef CValue<-N> type;

74
75
      static type eval(Negative<CValue<N> > const& t)
      { return CValue<-N>(); }
76

77
    };
78

79
80
    /// -0 -> 0
    template<>
81
82
    struct Simplify< Negative<CValue<0> > >
    {
83
      typedef CValue<0> type;
84
85

      static type eval(Negative<CValue<0> > const& t)
86
87
      { return CValue<0>(); }
    };
88

89
90
    /// (N) + (M) -> (N+M)
    template<int N, int M>
91
92
    struct Simplify< Add<CValue<N>, CValue<M> > >
    {
93
      typedef CValue<N+M> type;
94
95

      static type eval(Add<CValue<N>, CValue<M> > const& t)
96
97
      { return CValue<N+M>(); }
    };
98

99
100
    /// (N) - (M) -> (N-M)
    template<int N, int M>
101
102
    struct Simplify< Subtract<CValue<N>, CValue<M> > >
    {
103
      typedef CValue<N-M> type;
104
105

      static type eval(Subtract<CValue<N>, CValue<M> > const& t)
106
107
      { return CValue<N-M>(); }
    };
108

109
110
    /// (N) * (M) -> (N*M)
    template<int N, int M >
111
112
    struct Simplify< Mult<CValue<N>, CValue<M> > >
    {
113
      typedef CValue<N*M> type;
114
115

      static type eval(Mult<CValue<N>, CValue<M> > const& t)
116
117
      { return CValue<N*M>(); }
    };
118

119
120
    /// (M) ^ N -> (M^N)
    template<int N, int M >
121
122
    struct Simplify< Pow<N, CValue<M> > >
    {
123
      typedef CValue<meta::pow<M,N>::value> type;
124
125

      static type eval(Pow<N, CValue<M> > const& t)
126
127
      { return type(); }
    };
128

129
130
  } // end namespace expressions

131
  namespace expressions
132
133
134
  {
    /// X + 0 -> X
    template<typename Term>
135
    struct Simplify< Add<Term, CValue<0> > >
136
137
138
139
    {
      typedef typename Simplify<Term>::type type;

      static type eval(Add<Term, CValue<0> > const& t)
140
141
      { return simplify(t.term1); }
    };
142

143
144
145
    /// (N) + 0 -> X
    template<int N>
    struct Simplify< Add<CValue<N>, CValue<0> > >
146
147
148
149
    {
      typedef CValue<N> type;

      static type eval(Add<CValue<N>, CValue<0> > const&)
150
      { return CValue<N>(); }
Praetorius, Simon's avatar
Praetorius, Simon committed
151
    };
152

Praetorius, Simon's avatar
Praetorius, Simon committed
153
154
    /// X - 0 -> X
    template<typename Term>
155
    struct Simplify< Subtract<Term, CValue<0> > >
156
157
158
159
    {
      typedef typename Simplify<Term>::type type;

      static type eval(Subtract<Term, CValue<0> > const& t)
Praetorius, Simon's avatar
Praetorius, Simon committed
160
161
      { return simplify(t.term1); }
    };
162

163
164
165
    /// (N) - 0 -> (N)
    template<int N>
    struct Simplify< Subtract<CValue<N>, CValue<0> > >
166
167
168
169
    {
      typedef CValue<N> type;

      static type eval(Subtract<CValue<N>, CValue<0> > const&)
170
171
      { return CValue<N>(); }
    };
172

173
174
175
    /// 0 + X -> X
    template<typename Term>
    struct Simplify< Add<CValue<0>, Term> >
176
177
178
179
    {
      typedef typename Simplify<Term>::type type;

      static type eval(Add<CValue<0>, Term> const& t)
180
181
      { return simplify(t.term2); }
    };
182

183
184
185
    /// 0 + (N) -> (N)
    template<int N>
    struct Simplify< Add<CValue<0>, CValue<N> > >
186
187
188
189
    {
      typedef CValue<N> type;

      static type eval(Add<CValue<0>, CValue<N> > const&)
190
191
      { return CValue<N>(); }
    };
192

Praetorius, Simon's avatar
Praetorius, Simon committed
193
194
    /// 0 - X -> -X
    template<typename Term>
195
    struct Simplify< Subtract<CValue<0>, Term> >
196
197
198
199
    {
      typedef Negative<typename Simplify<Term>::type> type;

      static type eval(Subtract<CValue<0>, Term> const& t)
Praetorius, Simon's avatar
Praetorius, Simon committed
200
      { return -simplify(t.term2); }
201
    };
202

203
204
205
    /// 0 - (N) -> (-N)
    template<int N>
    struct Simplify< Subtract<CValue<0>, CValue<N> > >
206
207
208
209
    {
      typedef CValue<-N> type;

      static type eval(Subtract<CValue<0>, CValue<N> > const&)
210
211
      { return CValue<-N>(); }
    };
212

213
214
215
    /// 0 - 0 -> 0
    template<>
    struct Simplify< Subtract<CValue<0>, CValue<0> > >
216
217
218
219
    {
      typedef CValue<0> type;

      static type eval(Subtract<CValue<0>, CValue<0> > const&)
220
221
      { return type(); }
    };
222

223
224
225
    /// 0 + 0 -> 0
    template<>
    struct Simplify< Add<CValue<0>, CValue<0> > >
226
227
228
229
    {
      typedef CValue<0> type;

      static type eval(Add<CValue<0>, CValue<0> > const&)
230
231
      { return type(); }
    };
232

233
234
    /// X * 0 -> 0
    template<typename Term>
235
236
237
238
239
    struct Simplify< Mult<Term, CValue<0> > >
    {
      typedef CValue<0> type;

      static type eval(Mult<Term, CValue<0> > const&)
240
241
      { return CValue<0>(); }
    };
242

243
244
    /// (N) * 0 -> 0
    template<int N>
245
246
247
248
249
    struct Simplify< Mult<CValue<N>, CValue<0> > >
    {
      typedef CValue<0> type;

      static type eval(Mult<CValue<N>, CValue<0> > const&)
250
251
      { return CValue<0>(); }
    };
252

253
254
    /// 0 * X -> 0
    template<typename Term>
255
256
257
258
259
    struct Simplify< Mult<CValue<0>, Term> >
    {
      typedef CValue<0> type;

      static type eval(Mult<CValue<0>, Term> const& t)
260
261
      { return CValue<0>(); }
    };
262

263
264
    /// 0 * (N) -> 0
    template<int N>
265
266
267
268
269
    struct Simplify< Mult<CValue<0>, CValue<N> > >
    {
      typedef CValue<0> type;

      static type eval(Mult<CValue<0>, CValue<N> > const&)
270
271
      { return CValue<0>(); }
    };
272

273
274
    /// X * 1 -> X
    template<typename Term>
275
276
277
278
279
    struct Simplify< Mult<Term, CValue<1> > >
    {
      typedef typename Simplify<Term>::type type;

      static type eval(Mult<Term, CValue<1> > const& t)
280
281
      { return simplify(t.term1); }
    };
282

283
284
    /// (N) * 1 -> (N)
    template<int N>
285
286
287
288
289
    struct Simplify< Mult<CValue<N>, CValue<1> > >
    {
      typedef CValue<N> type;

      static type eval(Mult<CValue<N>, CValue<1> > const&)
290
291
      { return CValue<N>(); }
    };
292

293
294
    /// 1 * X -> X
    template<typename Term>
295
296
297
298
299
    struct Simplify< Mult<CValue<1>, Term> >
    {
      typedef typename Simplify<Term>::type type;

      static type eval(Mult<CValue<1>, Term> const& t)
300
301
      { return simplify(t.term2); }
    };
302

303
304
    /// 1 * (N) -> (N)
    template<int N>
305
306
307
308
309
    struct Simplify< Mult<CValue<1>, CValue<N> > >
    {
      typedef CValue<N> type;

      static type eval(Mult<CValue<1>, CValue<N> > const&)
310
311
      { return CValue<N>(); }
    };
312

313
314
    /// X * -1 -> -X
    template<typename Term>
315
316
317
318
319
    struct Simplify< Mult<Term, CValue<-1> > >
    {
      typedef Negative<typename Simplify<Term>::type> type;

      static type eval(Mult<Term, CValue<-1> > const& t)
320
321
      { return -simplify(t.term1); }
    };
322

323
324
    /// (N) * -1 -> (-N)
    template<int N>
325
326
327
328
329
    struct Simplify< Mult<CValue<N>, CValue<-1> > >
    {
      typedef CValue<-N> type;

      static type eval(Mult<CValue<N>, CValue<-1> > const&)
330
331
      { return CValue<-N>(); }
    };
332

333
334
    /// -1 * X -> -X
    template<typename Term>
335
336
337
338
339
    struct Simplify< Mult<CValue<-1>, Term> >
    {
      typedef Negative<typename Simplify<Term>::type> type;

      static type eval(Mult<CValue<-1>, Term> const& t)
340
341
      { return -simplify(t.term2); }
    };
342

343
344
    /// -1 * (N) -> (-N)
    template<int N>
345
346
347
348
349
    struct Simplify< Mult<CValue<-1>, CValue<N> > >
    {
      typedef CValue<-N> type;

      static type eval(Mult<CValue<-1>, CValue<N> > const&)
350
351
      { return type(); }
    };
352
353


354
355
356
357
358
#define MULT_CVALUE_IMPL(_A_,_B_) \
  template<> struct Simplify< Mult<CValue<_A_>, CValue<_B_> > > { \
    typedef CValue<_A_ * _B_> type; \
    static type eval(Mult<CValue<_A_>, CValue<_B_> > const&) { return type(); } \
  };
359

360
361
362
363
364
365
366
367
368
369
    // implement all specializations with special values
    MULT_CVALUE_IMPL(0,0)
    MULT_CVALUE_IMPL(0,1)
    MULT_CVALUE_IMPL(1,0)
    MULT_CVALUE_IMPL(1,1)
    MULT_CVALUE_IMPL(0,-1)
    MULT_CVALUE_IMPL(-1,0)
    MULT_CVALUE_IMPL(-1,-1)
    MULT_CVALUE_IMPL(1,-1)
    MULT_CVALUE_IMPL(-1,1)
370

371
372
  } // end namespace expressions

373

374
375
376
377
378
  namespace expressions
  {
    // move constants to the beginning of the expression
//     /// X * N -> N * X
//     template<int N, typename Term>
379
380
381
382
383
//     struct Simplify< Mult<Term, CValue<N> > >
//     {
//       typedef Mult<CValue<N>, Term> type;
//
//       static type eval(Mult<Term, CValue<N> > const& t)
384
385
//       { return CValue<N>() * t.term1; }
//     };
386

387
  } // end namespace expressions
388
389

  namespace expressions
390
391
392
  {
    /// X / X -> 1
    template<typename Term>
393
394
    struct Simplify< Mult<Term, MultInverse<Term> > >
    {
395
      typedef CValue<1> type;
396
397
398

      static type eval(Mult<Term, MultInverse<Term> > const& t)
      { return CValue<1>(); }
399
    };
400

401
402
    /// X / X -> 1
    template<typename Term>
403
404
    struct Simplify< Mult<MultInverse<Term>, Term> >
    {
405
      typedef CValue<1> type;
406
407

      static type eval(Mult<MultInverse<Term>, Term> const& t)
408
409
      { return CValue<1>(); }
    };
410

411
412
    /// -(-X) -> X
    template<typename Term>
413
414
    struct Simplify< Negative<Negative<Term> > >
    {
415
      typedef Term type;
416
417

      static type eval(Negative<Negative<Term> > const& t)
418
419
      { return t.term.term; }
    };
420

421
422
    /// (X^(-1))^(-1) -> X
    template<typename Term>
423
424
    struct Simplify< MultInverse<MultInverse<Term> > >
    {
425
      typedef Term type;
426
427

      static type eval(MultInverse<MultInverse<Term> > const& t)
428
429
      { return t.term.term; }
    };
430

431
    /// (X + (-Y)) -> X - Y
432
    template<typename X, typename Y>
433
434
    struct Simplify< Negative<Add<X, Negative<Y> > > >
    {
435
      typedef Subtract<X, Y> type;
436
437

      static type eval(Negative<Add<X, Negative<Y> > > const& t)
438
439
      { return t.term1 - t.term2.term; }
    };
440

441
442
    /// -(X - Y) -> Y - X
    template<typename X, typename Y>
443
444
    struct Simplify< Negative<Subtract<X, Y> > >
    {
445
      typedef Subtract<Y, X> type;
446
447

      static type eval(Negative<Subtract<X, Y> > const& t)
448
      { return t.term.term2 - t.term.term1; }
449
    };
450

451
  } // end namespace expressions
452
453
454


  namespace expressions
455
456
457
  {
    /// X^1 -> X
    template<typename Term>
458
    struct Simplify< Pow<1, Term> >
459
460
461
    {
      typedef Term type;

462
463
      static type eval(Pow<1,Term> const& t) { return t.term; }
    };
464

465
466
    /// X^0 -> 1
    template<typename Term>
467
    struct Simplify< Pow<0, Term> >
468
    {
469
      typedef CValue<1> type;
470

471
472
473
474
      static type eval(Pow<0,Term> const& t) { return CValue<1>(); }
    };

  } // end namespace expressions
475
476
477


  namespace expressions
478
479
480
  {
    /// (XY) / (XZ) -> Y/Z
    template<typename X, typename Y, typename Z>
481
482
483
484
    struct Simplify< Mult<Mult<X,Y>, MultInverse<Mult<X,Z> > > >
    {
      typedef Mult<Y, MultInverse<Z> > type;

485
      // Y = t.term1.term2, Z = t.term2.term.term2
486
487
      static type eval(Mult<Mult<X,Y>, MultInverse<Mult<X,Z> > > const& t)
      { return t.term1.term2 / t.term2.term.term2; }
488
    };
489

490
491
    /// (XY) / X -> Y
    template<typename X, typename Y>
492
493
    struct Simplify< Mult<Mult<X,Y>, MultInverse<X> > >
    {
494
      typedef Y type;
495

496
      // Y = t.term1.term2
497
      static type eval(Mult<Mult<X,Y>, MultInverse<X> > const& t)
498
499
      { return t.term1.term2; }
    };
500

501
502
    /// X / (XY) -> 1/Y
    template<typename X, typename Y>
503
504
    struct Simplify< Mult<X, MultInverse<Mult<X,Y> > > >
    {
505
      typedef MultInverse<Y> type;
506

507
      // Y = t.term2.term.term2
508
      static type eval(Mult<Mult<X,Y>, MultInverse<X> > const& t)
509
510
      { return MultInverse<Y>(t.term2.term.term2); }
    };
511

512
513
    /// N*(M*X) -> (N*M) * X
    template<int N, int M, typename X>
514
515
    struct Simplify< Mult<CValue<N>, Mult<CValue<M>, X> > >
    {
516
      typedef Mult<CValue<N*M>, X> type;
517

518
      // X = t.term2.term2
519
520
      static type eval(Mult<CValue<N>, Mult<CValue<M>, X> > const& t)
      { return CValue<N*M>() * (t.term2.term2); }
521
    };
522

523
524
    /// 0*(M*X) -> 0
    template<int M, typename X>
525
526
    struct Simplify< Mult<CValue<0>, Mult<CValue<M>, X> > >
    {
527
      typedef CValue<0> type;
528

529
      // X = t.term2.term2
530
531
      static type eval(Mult<CValue<0>, Mult<CValue<M>, X> > const& t)
      { return type(); }
532
    };
533

534
535
    /// 1*(M*X) -> M * X
    template<int M, typename X>
536
537
    struct Simplify< Mult<CValue<1>, Mult<CValue<M>, X> > >
    {
538
      typedef Mult<CValue<M>, X> type;
539

540
      // X = t.term2.term2
541
542
      static type eval(Mult<CValue<1>, Mult<CValue<M>, X> > const& t)
      { return CValue<M>() * (t.term2.term2); }
543
    };
544

545
546
    /// -1*(M*X) -> (-M) * X
    template<int M, typename X>
547
548
    struct Simplify< Mult<CValue<-1>, Mult<CValue<M>, X> > >
    {
549
      typedef Mult<CValue<-M>, X> type;
550

551
      // X = t.term2.term2
552
553
      static type eval(Mult<CValue<-1>, Mult<CValue<M>, X> > const& t)
      { return CValue<-M>() * (t.term2.term2); }
554
    };
555
556


557
558
    /// N*(X*M) -> (N*M) * X
    template<int N, int M, typename X>
559
560
561
562
    struct Simplify< Mult<CValue<N>, Mult<X, CValue<M> > > >
    {
      typedef Mult<CValue<N*M>, X> type;

563
      // X = t.term2.term1
564
565
      static type eval(Mult<CValue<N>, Mult<X, CValue<M> > > const& t)
      { return CValue<N*M>() * (t.term2.term1); }
566
    };
567

568
569
    /// 0*(X*M) -> 0
    template<int M, typename X>
570
571
572
573
    struct Simplify< Mult<CValue<0>, Mult<X, CValue<M> > > >
    {
      typedef CValue<0> type;

574
      // X = t.term2.term1
575
576
      static type eval(Mult<CValue<0>, Mult<X, CValue<M> > > const& t)
      { return type(); }
577
    };
578

579
580
    /// 1*(X*M) -> M * X
    template<int M, typename X>
581
582
583
584
    struct Simplify< Mult<CValue<1>, Mult<X, CValue<M> > > >
    {
      typedef Mult<CValue<M>, X> type;

585
      // X = t.term2.term1
586
587
      static type eval(Mult<CValue<1>, Mult<X, CValue<M> > > const& t)
      { return CValue<M>() * (t.term2.term1); }
588
    };
589

590
591
    /// -1*(X*M) -> (-M) * X
    template<int M, typename X>
592
593
594
595
    struct Simplify< Mult<CValue<-1>, Mult<X, CValue<M> > > >
    {
      typedef Mult<CValue<-M>, X> type;

596
      // X = t.term2.term1
597
598
      static type eval(Mult<CValue<-1>, Mult<X, CValue<M> > > const& t)
      { return CValue<-M>() * (t.term2.term1); }
599
    };
600
601


602
603
    /// (M*X)*N -> (N*M) * X
    template<int N, int M, typename X>
604
605
606
607
    struct Simplify< Mult<Mult<CValue<M>, X>, CValue<N> > >
    {
      typedef Mult<CValue<N*M>, X> type;

608
      // X = t.term1.term2
609
      static type eval(Mult<Mult<CValue<M>, X>, CValue<N> > const& t)
610
      { return CValue<N*M>() * (t.term1.term2); }
611
612
    };

613
614
    /// (M*X)*0 -> 0
    template<int M, typename X>
615
616
617
618
    struct Simplify< Mult<Mult<CValue<M>, X>, CValue<0> > >
    {
      typedef CValue<0> type;

619
      // X = t.term1.term2
620
      static type eval(Mult<Mult<CValue<M>, X>, CValue<0> > const& t)
621
622
      { return type(); }
    };
623

624
625
    /// (M*X)*1 -> M * X
    template<int M, typename X>
626
627
628
629
    struct Simplify< Mult<Mult<CValue<M>, X>, CValue<1> > >
    {
      typedef Mult<CValue<M>, X> type;

630
      // X = t.term1.term2
631
      static type eval(Mult<Mult<CValue<M>, X>, CValue<1> > const& t)
632
      { return CValue<M>() * (t.term1.term2); }
633
634
    };

635
636
    /// (M*X)*-1 -> (-M) * X
    template<int M, typename X>
637
638
639
640
    struct Simplify< Mult<Mult<CValue<M>, X>, CValue<-1> > >
    {
      typedef Mult<CValue<-M>, X> type;

641
      // X = t.term1.term2
642
      static type eval(Mult<Mult<CValue<M>, X>, CValue<-1> > const& t)
643
      { return CValue<-M>() * (t.term1.term2); }
644
    };
645
646


647
648
    /// (X*M)*N -> (N*M) * X
    template<int N, int M, typename X>
649
650
651
652
    struct Simplify< Mult<Mult<X, CValue<M> >, CValue<N> > >
    {
      typedef Mult<CValue<N*M>, X> type;

653
      // X = t.term1.term1
654
      static type eval(Mult<Mult<X, CValue<M> >, CValue<N> > const& t)
655
      { return CValue<N*M>() * (t.term1.term1); }
656
657
    };

658
659
    /// (X*M)*0 -> 0
    template<int M, typename X>
660
661
662
663
    struct Simplify< Mult<Mult<X, CValue<M> >, CValue<0> > >
    {
      typedef CValue<0> type;

664
      // X = t.term1.term1
665
      static type eval(Mult<Mult<X, CValue<M> >, CValue<0> > const& t)
666
667
      { return type(); }
    };
668

669
670
    /// (X*M)*1 -> M * X
    template<int M, typename X>
671
672
673
674
    struct Simplify< Mult<Mult<X, CValue<M> >, CValue<1> > >
    {
      typedef Mult<CValue<M>, X> type;

675
      // X = t.term1.term1
676
      static type eval(Mult<Mult<X, CValue<M> >, CValue<1> > const& t)
677
      { return CValue<M>() * (t.term1.term1); }
678
679
    };

680
681
    /// (X*M)*-1 -> (-M) * X
    template<int M, typename X>
682
683
684
685
    struct Simplify< Mult<Mult<X, CValue<M> >, CValue<-1> > >
    {
      typedef Mult<CValue<-M>, X> type;

686
      // X = t.term1.term1
687
      static type eval(Mult<Mult<X, CValue<M> >, CValue<-1> > const& t)
688
      { return CValue<-M>() * (t.term1.term1); }
689
690
691
    };


692
693
    /// X * (N * Y) -> N * (X * Y)
    template<typename X, int N, typename Y>
694
695
696
697
    struct Simplify< Mult<X, Mult<CValue<N>, Y> > >
    {
      typedef Mult<CValue<N>, Mult<X,Y> > type;

698
699
      // X = t.term1
      // Y = t.term2.term2
700
      static type eval(Mult<X, Mult<CValue<N>, Y> > const& t)
701
702
      { return CValue<N>() * (t.term1 * t.term2.term2); }
    };
703
704


705
706
    /// -(N*X) -> (-N) * X
    template<int N, typename X>
707
708
    struct Simplify< Negative<Mult<CValue<N>,X> > >
    {
709
      typedef Mult<CValue<-N>, typename Simplify<X>::type> type;
710

711
      // X = t.term.term2
712
      static type eval(Negative<Mult<CValue<N>,X> > const& t)
713
      { return CValue<-N>() * simplify(t.term.term2); }
714
715
716
717
718
    };

  } // end namespace expressions


719
  namespace expressions
720
721
722
  {
    /// A + B -> simplify(A) + simplify(B)
    template<typename Term1, typename Term2>
723
724
    class Simplify< Add<Term1, Term2> >
    {
725
726
      typedef typename Simplify<Term1>::type S1;
      typedef typename Simplify<Term2>::type S2;
727

728
729
    public:
      typedef Add<S1, S2> type;
730
731

      static type eval(Add<Term1, Term2> const& t)
732
733
734
735
      {
	return simplify(t.term1) + simplify(t.term2);
      }
    };
736

737
738
    /// A - B -> simplify(A) - simplify(B)
    template<typename Term1, typename Term2>
739
740
    class Simplify< Subtract<Term1, Term2> >
    {
741
742
      typedef typename Simplify<Term1>::type S1;
      typedef typename Simplify<Term2>::type S2;
743

744
745
    public:
      typedef Subtract<S1, S2> type;
746
747

      static type eval(Subtract<Term1, Term2> const& t)
748
749
750
751
      {
	return simplify(t.term1) - simplify(t.term2);
      }
    };
752

753
754
    /// A * B -> simplify(A) * simplify(B)
    template<typename Term1, typename Term2>
755
756
    class Simplify< Mult<Term1, Term2> >
    {
757
758
      typedef typename Simplify<Term1>::type S1;
      typedef typename Simplify<Term2>::type S2;
759

760
761
    public:
      typedef Mult<S1, S2> type;
762
763

      static type eval(Mult<Term1, Term2> const& t)
764
765
766
767
      {
	return simplify(t.term1) * simplify(t.term2);
      }
    };
768

769
770
    /// X(A) -> X(simplify(A))
    template<template<class> class Outer, class Inner>
771
772
    class Simplify< Outer<Inner> >
    {
773
      typedef typename Simplify<Inner>::type S;
774

775
776
    public:
      typedef Outer<S> type;
777
778

      static type eval(Outer<Inner> const& t)
779
780
781
782
783
784
785
786
787
788
789
      {
	return type(simplify(t.term));
      }
    };

  } // end namespace expressions


  // =============================================================================
  // multiple simplifications

790
791
  namespace expressions
  {
792
    template<int N, typename Term, typename Enabled = void>
793
794
    struct SimplifyRecursive
    {
795
796
      typedef typename Simplify< typename SimplifyRecursive<N-1, Term>::type >::type type;
    };
797

798
799
    template<typename Term>
    struct SimplifyRecursive<1, Term>
800
    {
801
802
      typedef typename Simplify< Term >::type type;
    };
803

804
805
    template<int N, typename Term >
    struct SimplifyRecursive<N, Term, typename boost::enable_if_c<(N <= 0)>::type>
806
    {
807
808
      typedef Term type;
    };
809

810
811
  } // end namespace expressions

812
813

  template<int N, typename Term>
814
815
816
  inline typename expressions::SimplifyRecursive<N, Term>::type
  simplify(const Term& t);

817
  template<int N, typename Term>
818
819
820
  inline typename expressions::SimplifyRecursive<N, Term>::type
  simplify(const Term& t, boost::mpl::int_<N>) { return simplify(simplify<N-1>(t)); }

821
  template<typename Term>
822
823
824
  inline typename expressions::SimplifyRecursive<1, Term>::type
  simplify(const Term& t, boost::mpl::int_<1>) { return simplify(t); }

825
  template<typename Term>
826
827
828
  inline typename expressions::SimplifyRecursive<0, Term>::type
  simplify(const Term& t, boost::mpl::int_<0>) { return t; }

829
  template<int N, typename Term>
830
831
832
833
834
835
  inline typename expressions::SimplifyRecursive<N, Term>::type
  simplify(const Term& t) { return simplify(t, boost::mpl::int_<N>()); }

} // end namespace AMDiS

#endif // AMDIS_SIMPLIFY_EXPRESSION_HPP