From 2aa7c90c490d406bc6bf3a194514c2f0d5b88382 Mon Sep 17 00:00:00 2001
From: LABOURASSE Emmanuel <labourassee@gmail.com>
Date: Fri, 21 Aug 2020 19:00:45 +0200
Subject: [PATCH] divide polynomials and attempt to build Lagrange basis

---
 src/analysis/Polynomial.hpp | 77 +++++++++++++++++++++++++++++++++++++
 tests/test_Polynomial.cpp   | 36 +++++++++++++++++
 2 files changed, 113 insertions(+)

diff --git a/src/analysis/Polynomial.hpp b/src/analysis/Polynomial.hpp
index a2e82f9c1..c768d2d67 100644
--- a/src/analysis/Polynomial.hpp
+++ b/src/analysis/Polynomial.hpp
@@ -12,6 +12,23 @@ class Polynomial
   static_assert((N >= 0), "Polynomial degree must be non-negative");
 
  public:
+  PUGS_INLINE
+  constexpr size_t
+  degree() const
+  {
+    return N;
+  }
+  PUGS_INLINE
+  constexpr size_t
+  realDegree() const
+  {
+    for (size_t j = N; j > 0; j--) {
+      if (std::abs(coefficients()[j]) > 1.e-14) {
+        return j;
+      }
+    }
+    return 0;
+  }
   PUGS_INLINE
   constexpr const TinyVector<N + 1>&
   coefficients() const
@@ -64,6 +81,14 @@ class Polynomial
     return P;
   }
 
+  PUGS_INLINE constexpr Polynomial<N>
+  operator-() const
+  {
+    Polynomial<N> P;
+    P.coefficients() = -coefficients();
+    return P;
+  }
+
   template <size_t M>
   PUGS_INLINE constexpr Polynomial<std::max(M, N)>
   operator-(const Polynomial<M>& Q) const
@@ -109,6 +134,17 @@ class Polynomial
     return *this;
   }
 
+  template <size_t M>
+  PUGS_INLINE constexpr Polynomial<N>&
+  operator-=(const Polynomial<M>& Q)
+  {
+    static_assert(N >= M, "Polynomial degree to small in affectation addition");
+    for (size_t i = 0; i <= M; ++i) {
+      coefficients()[i] -= Q.coefficients()[i];
+    }
+    return *this;
+  }
+
   template <size_t M>
   PUGS_INLINE constexpr Polynomial<M + N> operator*(const Polynomial<M>& Q) const
   {
@@ -230,6 +266,25 @@ class Polynomial
     return bcoef;
   }
 
+  template <size_t M>
+  PUGS_INLINE constexpr friend void
+  divide(const Polynomial<N>& P1, const Polynomial<M>& P2, Polynomial<N>& Q, Polynomial<N>& R)
+  {
+    const size_t Nr  = P1.realDegree();
+    const size_t Mr  = P2.realDegree();
+    R.coefficients() = P1.coefficients();
+    Q.coefficients() = zero;
+    for (size_t k = Nr - Mr + 1; k > 0; --k) {
+      Q.coefficients()[k - 1] = R.coefficients()[Mr + k - 1] / P2.coefficients()[Mr];
+      for (size_t j = Mr + k - 1; j > (k - 1); --j) {
+        R.coefficients()[j] -= Q.coefficients()[k - 1] * P2.coefficients()[j - k];
+      }
+    }
+    for (size_t j = Mr; j < Nr + 1; ++j) {
+      R.coefficients()[j] = 0;
+    }
+  }
+
   PUGS_INLINE
   constexpr friend Polynomial<N + 1>
   primitive(const Polynomial<N>& P)
@@ -342,6 +397,28 @@ class Polynomial
     }
   }
 
+  PUGS_INLINE
+  constexpr friend void
+  lagrangeBasis(const TinyVector<N + 1> zeros, TinyVector<N + 1, Polynomial<N>>& basis)
+  {
+    Polynomial<N> lj;
+    for (size_t j = 0; j < N + 1; ++j) {
+      lagrangePolynomial(zeros, j, basis[j]);
+    }
+  }
+
+  PUGS_INLINE
+  constexpr Polynomial<N>
+  lagrangeToCanonical(const TinyVector<N + 1> lagrange_coefs, TinyVector<N + 1, Polynomial<N>>& basis)
+  {
+    Polynomial<N> P(zero);
+    //    lagrangeBasis({0, 0, 0}, basis);
+    for (size_t j = 0; j < N + 1; ++j) {
+      P += basis[j] * lagrange_coefs[j];
+    }
+    return P;
+  }
+
   PUGS_INLINE constexpr Polynomial(const TinyVector<N + 1>& coefficients) noexcept : m_coefficients{coefficients} {}
 
   PUGS_INLINE
diff --git a/tests/test_Polynomial.cpp b/tests/test_Polynomial.cpp
index a935d3992..7c8951c90 100644
--- a/tests/test_Polynomial.cpp
+++ b/tests/test_Polynomial.cpp
@@ -24,6 +24,11 @@ TEST_CASE("Polynomial", "[analysis]")
   {
     REQUIRE_NOTHROW(Polynomial<2>{{2, 3, 4}});
   }
+  SECTION("degree")
+  {
+    Polynomial<2> P({2, 3, 4});
+    REQUIRE(P.degree() == 2);
+  }
   SECTION("equality")
   {
     Polynomial<2> P({2, 3, 4});
@@ -43,6 +48,12 @@ TEST_CASE("Polynomial", "[analysis]")
     REQUIRE(S == (P + Q));
     REQUIRE((T + P) == U);
   }
+  SECTION("opposed")
+  {
+    Polynomial<2> P({2, 3, 4});
+    Polynomial<2> Q = -P;
+    REQUIRE(Q == Polynomial<2>({-2, -3, -4}));
+  }
   SECTION("difference")
   {
     Polynomial<2> P({2, 3, 4});
@@ -52,6 +63,8 @@ TEST_CASE("Polynomial", "[analysis]")
     Polynomial<3> R({2, 3, 4, 1});
     REQUIRE(D == (P - Q));
     REQUIRE((P - R) == Polynomial<3>({0, 0, 0, -1}));
+    R -= P;
+    REQUIRE(R == Polynomial<3>({0, 0, 0, 1}));
   }
   SECTION("product_by_scalar")
   {
@@ -73,6 +86,22 @@ TEST_CASE("Polynomial", "[analysis]")
     REQUIRE(Polynomial<5>({2, 7, 8, 7, -1, 4}) == S);
     // REQUIRE_THROWS_AS(R *= Q, AssertError);
   }
+  SECTION("divide")
+  {
+    Polynomial<2> P({1, 0, 1});
+    Polynomial<1> Q({0, 1});
+    Polynomial<1> Q1({0, 1});
+
+    Polynomial<2> R;
+    Polynomial<2> S;
+    REQUIRE(P.realDegree() == 2);
+    REQUIRE(Q.realDegree() == 1);
+    REQUIRE(Q1.realDegree() == 1);
+
+    divide(P, Q1, R, S);
+    REQUIRE(Polynomial<2>({1, 0, 0}) == S);
+    REQUIRE(Polynomial<2>({0, 1, 0}) == R);
+  }
   SECTION("evaluation")
   {
     Polynomial<2> P({2, -3, 4});
@@ -158,5 +187,12 @@ TEST_CASE("Polynomial", "[analysis]")
     Polynomial<2> R;
     lagrangePolynomial({-1, 0, 1}, 0, R);
     REQUIRE(R == P);
+    TinyVector<2, Polynomial<2>> basis;
+    //    lagrangeBasis<2>({-1,0,1},basis);
+    basis[0] = Polynomial<2>({0, -0.5, 0.5});
+    basis[1] = Polynomial<2>({1, 0, -1});
+    basis[2] = Polynomial<2>({0, 0.5, 0.5});
+    // Q = lagrangeToCanonical({1,0,1},basis);
+    // REQUIRE(lagrangeToCanonical<2>({1, 0, 1}, basis) == Polynomial<2>({0, 0, 1}));
   }
 }
-- 
GitLab