From 0e5133223d7aded0d81d22c3330807d203c0a3aa Mon Sep 17 00:00:00 2001
From: labourasse <labourassee@gmail.com>
Date: Thu, 30 Jun 2022 15:58:58 +0200
Subject: [PATCH] dd evaluation feature with multi-D Horner method

---
 src/analysis/PolynomialP.hpp | 57 +++++++++++++++++++++++++++++++++++-
 tests/test_PolynomialP.cpp   | 42 +++++++++++++++++++++-----
 2 files changed, 90 insertions(+), 9 deletions(-)

diff --git a/src/analysis/PolynomialP.hpp b/src/analysis/PolynomialP.hpp
index 5712e5ef5..b76fe6559 100644
--- a/src/analysis/PolynomialP.hpp
+++ b/src/analysis/PolynomialP.hpp
@@ -2,6 +2,7 @@
 #define POLYNOMIALP_HPP
 
 #include <algebra/TinyVector.hpp>
+#include <utils/Exceptions.hpp>
 
 template <size_t N, size_t Dimension>
 class PolynomialP
@@ -141,7 +142,7 @@ class PolynomialP
 
   PUGS_INLINE
   constexpr double
-  coef(const TinyVector<Dimension, size_t> relative_pos) const
+  operator[](const TinyVector<Dimension, size_t> relative_pos) const
   {
     size_t total_degree = 0;
     for (size_t i = 0; i < Dimension; ++i) {
@@ -153,9 +154,63 @@ class PolynomialP
                                 "degree of the polynomial");
     TinyVector<size_coef> absolute_coefs = this->coefficients();
     size_t absolute_position             = 0;
+    if constexpr (Dimension == 1) {
+      absolute_position = relative_pos[0];
+    } else if constexpr (Dimension == 2) {
+      size_t total_degree = relative_pos[0] + relative_pos[1];
+      absolute_position   = total_degree * (total_degree + 1) / 2 + relative_pos[1];
+    } else {
+      throw UnexpectedError("Not yet Available in 3D");
+      // static_assert(Dimension == 3);
+      // size_t total_degree = relative_pos[0] + relative_pos[1] + relative_pos[2];
+      // return (total_degree + 1) * (total_degree + 2) * (total_degree + 3) / 6 + relative_pos[1];
+      // return (N + 1) * (N + 2) * (N + 3) / 6;
+    }
+
     return absolute_coefs[absolute_position];
   }
 
+  PUGS_INLINE
+  constexpr double
+  operator()(const TinyVector<Dimension> x) const
+  {
+    const auto& P = *this;
+    double value  = 0.;
+    if constexpr (Dimension == 1) {
+      value = m_coefficients[N];
+      for (size_t i = N; i > 0; --i) {
+        value *= x;
+        value += m_coefficients[i - 1];
+      }
+    } else if constexpr (Dimension == 2) {
+      TinyVector<Dimension, size_t> relative_pos(0, N);
+      value = P[relative_pos];
+      for (size_t i = N; i > 0; --i) {
+        value *= x[1];
+        relative_pos  = TinyVector<2, size_t>(N - i + 1, i - 1);
+        double valuex = P[relative_pos];
+        for (size_t j = N - i + 1; j > 0; --j) {
+          valuex *= x[0];
+          relative_pos = TinyVector<2, size_t>(j - 1, i - 1);
+          valuex += P[relative_pos];
+        }
+        value += valuex;
+      }
+      // relative_pos  = TinyVector<2, size_t>(N, 0);
+      // double valuex = P[relative_pos];
+      // for (size_t j = N; j > 0; --j) {
+      //   valuex *= x[0];
+      //   relative_pos = TinyVector<2, size_t>(j - 1, 0);
+      //   valuex += P[relative_pos];
+      // }
+      // value += valuex;
+    } else {
+      throw UnexpectedError("Not yet Available in 3D");
+    }
+
+    return value;
+  }
+
   PUGS_INLINE constexpr PolynomialP() noexcept = default;
   ~PolynomialP()                               = default;
 };
diff --git a/tests/test_PolynomialP.cpp b/tests/test_PolynomialP.cpp
index 1a9b6dbc6..d6323a37b 100644
--- a/tests/test_PolynomialP.cpp
+++ b/tests/test_PolynomialP.cpp
@@ -87,11 +87,43 @@ TEST_CASE("PolynomialP", "[analysis]")
     REQUIRE(Q == (2 * P));
   }
 
-  // SECTION("product")
+  SECTION("access_coef")
+  {
+    TinyVector<6> coef(1, -2, 10, 7, 2, 9);
+    TinyVector<10> coef2(2, -4, -1, -3, 3, -5, -6, 0, 1, 7);
+    PolynomialP<2, 2> P(coef);
+    PolynomialP<3, 2> Q(coef2);
+    TinyVector<2, size_t> relative_coef(1, 1);
+    TinyVector<2, size_t> relative_coef2(1, 2);
+    REQUIRE(P[relative_coef] == 2);
+    REQUIRE(Q[relative_coef2] == 1);
+    REQUIRE(Q[relative_coef] == 3);
+  }
+
+  SECTION("evaluation")
+  {
+    TinyVector<6> coef(1, -2, 10, 7, 2, 9);
+    TinyVector<10> coef2(2, -4, -1, -3, 3, -5, -6, 0, 1, 7);
+    PolynomialP<2, 2> P(coef);
+    PolynomialP<3, 2> Q(coef2);
+    TinyVector<6> coefx(1, -2, 0, 7, 0, 0);
+    TinyVector<6> coefy(2, 0, -2, 0, 0, 7);
+    TinyVector<2> pos(1, -1);
+    TinyVector<2> pos2(-1, 2);
+    PolynomialP<2, 2> Px(coefx);
+    PolynomialP<2, 2> Py(coefy);
+    REQUIRE(Px(pos) == 6);
+    REQUIRE(Py(pos) == 11);
+    REQUIRE(Px(pos2) == 10);
+    REQUIRE(P(pos2) == 62);
+    REQUIRE(Q(pos) == -20);
+  }
+
+  // // SECTION("product")
   // {
   //   Polynomial<2> P(2, 3, 4);
   //   Polynomial<3> Q(1, 2, -1, 1);
-  //   Polynomial<4> R;
+  //   Polynomial<4 > R;
   //   Polynomial<5> S;
   //   R = P;
   //   S = P;
@@ -118,12 +150,6 @@ TEST_CASE("PolynomialP", "[analysis]")
   //   REQUIRE(Polynomial<2>{0, 1, 0} == R);
   // }
 
-  // SECTION("evaluation")
-  // {
-  //   Polynomial<2> P(2, -3, 4);
-  //   REQUIRE(P(3) == 29);
-  // }
-
   // SECTION("primitive")
   // {
   //   Polynomial<2> P(2, -3, 4);
-- 
GitLab