From 562973be86f0597ef313d4b07580c0ea18c24e96 Mon Sep 17 00:00:00 2001
From: Simon Praetorius <simon.praetorius@tu-dresden.de>
Date: Sun, 17 Mar 2019 11:06:34 +0100
Subject: [PATCH] make some operations constexpr and add missing inline

---
 src/amdis/operations/Arithmetic.hpp | 36 ++++++-------
 src/amdis/operations/CMath.hpp      |  2 +-
 test/CMakeLists.txt                 |  3 ++
 test/OperationsTest.cpp             | 82 +++++++++++++++++++++++++++++
 4 files changed, 104 insertions(+), 19 deletions(-)
 create mode 100644 test/OperationsTest.cpp

diff --git a/src/amdis/operations/Arithmetic.hpp b/src/amdis/operations/Arithmetic.hpp
index 31d7c7a8..f3580e77 100644
--- a/src/amdis/operations/Arithmetic.hpp
+++ b/src/amdis/operations/Arithmetic.hpp
@@ -43,13 +43,13 @@ namespace AMDiS
 #endif
 
     template <class... Int>
-    int order(Plus, Int... orders)
+    constexpr int order(Plus, Int... orders)
     {
       return Math::max(int(orders)...);
     }
 
     template <std::size_t I>
-    auto partial(Plus, index_t<I>)
+    constexpr auto partial(Plus, index_t<I>)
     {
       static_assert((I < 2), "Derivatives of `Plus` only defined for the binary case.");
       return One{};
@@ -66,17 +66,17 @@ namespace AMDiS
         return lhs - rhs;
       }
 
-      friend int order(Minus, int lhs, int rhs)
+      friend constexpr int order(Minus, int lhs, int rhs)
       {
         return Math::max(lhs, rhs);
       }
 
-      friend auto partial(Minus, index_t<0>)
+      friend constexpr auto partial(Minus, index_t<0>)
       {
         return One{};
       }
 
-      friend auto partial(Minus, index_t<1>)
+      friend constexpr auto partial(Minus, index_t<1>)
       {
         return StaticConstant<int,-1>{};
       }
@@ -134,15 +134,15 @@ namespace AMDiS
 
 
     template <class... Int>
-    int order(Multiplies, Int... orders)
+    constexpr int order(Multiplies, Int... orders)
     {
-      return Plus{}(int(orders)...);
+      return Math::sum(int(orders)...);
     }
 
     // only for binary *
     // d_0 (x * y) = y, d_1 (x * y) = x
     template <std::size_t I>
-    auto partial(Multiplies, index_t<I>)
+    constexpr auto partial(Multiplies, index_t<I>)
     {
       static_assert((I < 2), "Derivatives of `Multiplies` only defined for the binary case.");
       return Arg<1-I>{};
@@ -160,13 +160,13 @@ namespace AMDiS
       }
 
       // d_0 f(x,y) = 1 / y
-      friend auto partial(Divides, index_t<0>)
+      friend constexpr auto partial(Divides, index_t<0>)
       {
         return compose(Divides{}, One{}, Arg<1>{});
       }
 
       // d_1 f(x,y) = (y - x)/y^2
-      friend auto partial(Divides, index_t<1>);
+      friend constexpr auto partial(Divides, index_t<1>);
     };
 
     // -------------------------------------------------------------------------
@@ -180,12 +180,12 @@ namespace AMDiS
         return -x;
       }
 
-      friend int order(Negate, int d)
+      friend constexpr int order(Negate, int d)
       {
         return d;
       }
 
-      friend auto partial(Negate, index_t<0>)
+      friend constexpr auto partial(Negate, index_t<0>)
       {
         return StaticConstant<int,-1>{};
       }
@@ -238,12 +238,12 @@ namespace AMDiS
         return Math::pow<p>(x);
       }
 
-      friend int order(PowImpl, int d)
+      friend constexpr int order(PowImpl, int d)
       {
         return p*d;
       }
 
-      friend auto partial(PowImpl, index_t<0>)
+      friend constexpr auto partial(PowImpl, index_t<0>)
       {
         return compose(Multiplies{}, StaticConstant<int,p>{}, Pow<p-1>{});
       }
@@ -278,7 +278,7 @@ namespace AMDiS
 #endif
 
     // d_1 f(x,y) = (y - x)/y^2
-    auto partial(Divides, index_t<1>)
+    inline constexpr auto partial(Divides, index_t<1>)
     {
       return compose(Divides{}, compose(Minus{}, Arg<1>{}, Arg<0>{}),
                                 compose(Pow<2>{}, Arg<1>{}));
@@ -287,7 +287,7 @@ namespace AMDiS
     /// Functor that represents x^p, \see \ref Pow
     struct Pow_
     {
-      Pow_(int p)
+      constexpr Pow_(int p)
         : p_(p)
       {}
 
@@ -297,12 +297,12 @@ namespace AMDiS
         return std::pow(x, p_);
       }
 
-      friend int order(Pow_ P, int d)
+      friend constexpr int order(Pow_ P, int d)
       {
         return P.p_ * d;
       }
 
-      friend auto partial(Pow_ P, index_t<0>)
+      friend constexpr auto partial(Pow_ P, index_t<0>)
       {
         return compose(Multiplies{}, Constant<int>{P.p_}, Pow_{P.p_-1});
       }
diff --git a/src/amdis/operations/CMath.hpp b/src/amdis/operations/CMath.hpp
index c90d5416..e865582f 100644
--- a/src/amdis/operations/CMath.hpp
+++ b/src/amdis/operations/CMath.hpp
@@ -52,7 +52,7 @@ namespace AMDiS
         return (x > T{0} ? T{1} : T{-1});
       }
 
-      constexpr friend auto partial(Signum, index_t<0>)
+      friend constexpr auto partial(Signum, index_t<0>)
       {
         return Zero{};
       }
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index ead7e40c..b08e5078 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -43,6 +43,9 @@ dune_add_test(SOURCES MultiTypeVectorTest.cpp
 dune_add_test(SOURCES MultiTypeMatrixTest.cpp
   LINK_LIBRARIES amdis)
 
+dune_add_test(SOURCES OperationsTest.cpp
+  LINK_LIBRARIES amdis)
+
 dune_add_test(SOURCES OperatorsTest.cpp
   LINK_LIBRARIES amdis)
 
diff --git a/test/OperationsTest.cpp b/test/OperationsTest.cpp
new file mode 100644
index 00000000..dfea8c33
--- /dev/null
+++ b/test/OperationsTest.cpp
@@ -0,0 +1,82 @@
+// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+// vi: set et ts=4 sw=2 sts=2:
+
+#include <iostream>
+
+#include <amdis/AMDiS.hpp>
+#include <amdis/Operations.hpp>
+#include "Tests.hpp"
+
+using namespace AMDiS;
+
+int main(int argc, char** argv)
+{
+  AMDiS::init(argc, argv);
+
+  constexpr Operation::StaticConstant<int,0> op0a;
+  constexpr Operation::Zero op0b;
+  AMDIS_TEST_EQ(order(op0a,4,2,6,3,4), 0);
+  AMDIS_TEST_EQ(order(op0b,4,2,6,3,4), 0);
+
+  constexpr int zero = op0a(1,2,3,4,5);
+  AMDIS_TEST_EQ(zero, 0);
+
+  constexpr Operation::StaticConstant<int,1> op1a;
+  constexpr Operation::One op1b;
+  AMDIS_TEST_EQ(order(op1a,4,2,6,3,4), 0);
+  AMDIS_TEST_EQ(order(op1b,4,2,6,3,4), 0);
+
+  constexpr int one = op1a(1,2,3,4,5);
+  AMDIS_TEST_EQ(one, 1);
+
+  constexpr auto op1a_0 = partial(op1a, index_t<0>{});
+  AMDIS_TEST((std::is_same<decltype(op1a_0), decltype(op0a)>::value));
+
+  constexpr Operation::Id op2;
+  AMDIS_TEST_EQ(op2(7), 7);
+  AMDIS_TEST_EQ(order(op2,7), 7);
+
+  constexpr Operation::Constant<int> op3(42);
+  AMDIS_TEST_EQ(op3(1,2,3,4,5), 42);
+  AMDIS_TEST_EQ(order(op3,4,2,6,3,4), 0);
+
+  constexpr Operation::Arg<0> op4a;
+  constexpr Operation::Arg<1> op4b;
+  AMDIS_TEST_EQ(op4a(1,2,3,4,5), 1);
+  AMDIS_TEST_EQ(op4b(1,2,3,4,5), 2);
+  AMDIS_TEST_EQ(order(op4a,4,2,6,3,4), 4);
+  AMDIS_TEST_EQ(order(op4b,4,2,6,3,4), 2);
+
+  constexpr Operation::Plus op5;
+  constexpr auto erg5 = op5(7,8);
+  constexpr int order5 = order(op5,2,3);
+  AMDIS_TEST_EQ(erg5, 15);
+  AMDIS_TEST_EQ(order5, 3);
+
+  constexpr Operation::Minus op6;
+  constexpr auto erg6 = op6(15,8);
+  constexpr int order6 = order(op6,2,3);
+  AMDIS_TEST_EQ(erg6, 7);
+  AMDIS_TEST_EQ(order6, 3);
+
+  constexpr Operation::Multiplies op7;
+  constexpr auto erg7 = op7(2,4);
+  constexpr int order7 = order(op7,2,3);
+  AMDIS_TEST_EQ(erg7, 8);
+  AMDIS_TEST_EQ(order7, 5);
+
+  constexpr auto op7_0 = partial(op7, index_t<0>{});
+  constexpr auto op7_1 = partial(op7, index_t<1>{});
+  constexpr auto erg7_0 = op7_0(2,4);
+  constexpr auto erg7_1 = op7_1(2,4);
+  AMDIS_TEST_EQ(erg7_0, 4);
+  AMDIS_TEST_EQ(erg7_1, 2);
+
+  constexpr Operation::Divides op8;
+  constexpr auto erg8 = op8(16,8);
+  AMDIS_TEST_EQ(erg8, 2);
+  // constexpr int order8 = order(op8,2,3); // no order() for divides
+
+  AMDiS::finalize();
+  return report_errors();
+}
-- 
GitLab