From 24233ee85ef7e395278f67e1d4131997f9b3e8d8 Mon Sep 17 00:00:00 2001 From: LABOURASSE Emmanuel <labourassee@gmail.com> Date: Wed, 22 Jul 2020 18:19:22 +0200 Subject: [PATCH] debut du codage de la classe polynome --- src/analysis/Polynomial.hpp | 165 ++++++++++++++++++++++++++++++++++++ tests/test_Polynomial.cpp | 70 +++++++++++++++ 2 files changed, 235 insertions(+) create mode 100644 src/analysis/Polynomial.hpp create mode 100644 tests/test_Polynomial.cpp diff --git a/src/analysis/Polynomial.hpp b/src/analysis/Polynomial.hpp new file mode 100644 index 000000000..4d9941996 --- /dev/null +++ b/src/analysis/Polynomial.hpp @@ -0,0 +1,165 @@ +#ifndef POLYNOMIAL_HPP +#define POLYNOMIAL_HPP + +#include <algebra/TinyVector.hpp> + +template <size_t N> +class Polynomial +{ + private: + using Coefficients = TinyVector<N + 1, double>; + Coefficients m_coefficients; + + public: + PUGS_INLINE + constexpr const TinyVector<N + 1>& + coefficients() const + { + return m_coefficients; + } + + PUGS_INLINE + constexpr TinyVector<N + 1>& + coefficients() + { + return m_coefficients; + } + + PUGS_INLINE + constexpr bool + operator==(const Polynomial<N>& q) const + { + if (m_coefficients != q.coefficients()) { + return false; + } + return true; + } + + PUGS_INLINE + constexpr bool + operator!=(const Polynomial<N>& q) const + { + return not this->operator==(q); + } + + PUGS_INLINE + constexpr Polynomial<N> + operator+(const Polynomial<N>& q) const + { + TinyVector<N + 1> sum_coefs = m_coefficients + q.coefficients(); + Polynomial<N> S(sum_coefs); + return S; + } + + PUGS_INLINE + constexpr Polynomial<N> + operator-(const Polynomial<N>& q) const + { + TinyVector<N + 1> diff_coefs = m_coefficients - q.coefficients(); + Polynomial<N> D(diff_coefs); + return D; + } + + PUGS_INLINE + constexpr Polynomial<N> operator*(const double& lambda) const + { + TinyVector<N + 1> mult_coefs = lambda * m_coefficients; + Polynomial<N> M(mult_coefs); + return M; + } + + PUGS_INLINE + constexpr friend Polynomial<N> operator*(const double& lambda, const Polynomial<N> P) + { + return P * lambda; + } + // evaluation using Horner's method https://en.wikipedia.org/wiki/Horner's_method + PUGS_INLINE + constexpr double + evaluate(const double& x) const + { + TinyVector<N + 1> coefs = this->coefficients(); + double bcoef = coefs[N]; + for (size_t i = N; i > 0; --i) { + bcoef *= x; + bcoef += coefs[i - 1]; + } + return bcoef; + } + + PUGS_INLINE + constexpr double + operator()(const double x) const + { + TinyVector<N + 1> coefs = this->coefficients(); + double bcoef = coefs[N]; + for (size_t i = N; i > 0; --i) { + bcoef *= x; + bcoef += coefs[i - 1]; + } + return bcoef; + } + + PUGS_INLINE + constexpr friend Polynomial<N + 1> + primitive(const Polynomial<N>& P) + { + TinyVector<N + 2> coefs; + for (size_t i = 0; i < N + 1; ++i) { + coefs[i + 1] = P.coefficients()[i] / double(i + 1); + } + coefs[0] = 0; + return Polynomial<N + 1>{coefs}; + } + + PUGS_INLINE + constexpr friend std::ostream& + operator<<(std::ostream& os, const Polynomial<N>& P) + { + // os << "P(x) = "; + bool all_coef_zero = true; + for (size_t i = N; i > 1; --i) { + if (P.coefficients()[i] != 0.) { + if (P.coefficients()[i] != 1 && P.coefficients()[i] != -1) { + os << std::abs(P.coefficients()[i]); + } + os << "x^" << i; + if (P.coefficients()[i - 1] > 0.) + os << " + "; + else + os << " - "; + all_coef_zero = false; + } else { + os << " "; + } + } + if (P.coefficients()[1] != 0.) { + if (P.coefficients()[1] != 1 && P.coefficients()[1] != -1) { + os << std::abs(P.coefficients()[1]); + } + os << "x"; + if (P.coefficients()[0] > 0.) + os << " + "; + else if (P.coefficients()[0] < 0.) + os << " - "; + all_coef_zero = false; + } else { + os << " "; + } + if (P.coefficients()[0] != 0. || all_coef_zero) + os << std::abs(P.coefficients()[0]); + return os; + } + + PUGS_INLINE + constexpr Polynomial(const TinyVector<N + 1>& coefficients) noexcept : m_coefficients{coefficients} {} + + PUGS_INLINE + constexpr Polynomial(TinyVector<N + 1>&& coefficients) noexcept : m_coefficients{coefficients} {} + + PUGS_INLINE + constexpr Polynomial() noexcept = default; + ~Polynomial() = default; +}; + +#endif // POLYNOMIAL_HPP diff --git a/tests/test_Polynomial.cpp b/tests/test_Polynomial.cpp new file mode 100644 index 000000000..214be6ca8 --- /dev/null +++ b/tests/test_Polynomial.cpp @@ -0,0 +1,70 @@ +#include <catch2/catch.hpp> + +#include <Kokkos_Core.hpp> + +#include <utils/PugsAssert.hpp> +#include <utils/Types.hpp> + +#include <algebra/TinyMatrix.hpp> +#include <analysis/Polynomial.hpp> + +// Instantiate to ensure full coverage is performed +template class Polynomial<1>; +template class Polynomial<2>; +template class Polynomial<3>; +template class Polynomial<4>; + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("Polynomial", "[analysis]") +{ + SECTION("construction") + { + REQUIRE_NOTHROW(Polynomial<2>{{2, 3, 4}}); + } + SECTION("equality") + { + Polynomial<2> P({2, 3, 4}); + Polynomial<2> Q({2, 3, 4}); + + REQUIRE(P == Q); + } + SECTION("addition") + { + Polynomial<2> P({2, 3, 4}); + Polynomial<2> Q({-1, -3, 2}); + Polynomial<2> S({1, 0, 6}); + REQUIRE(S == (P + Q)); + } + SECTION("difference") + { + Polynomial<2> P({2, 3, 4}); + Polynomial<2> Q({3, 4, 5}); + Polynomial<2> D({-1, -1, -1}); + REQUIRE(D == (P - Q)); + } + SECTION("product_by_scalar") + { + Polynomial<2> P({2, 3, 4}); + Polynomial<2> M({6, 9, 12}); + REQUIRE(M == (P * 3)); + REQUIRE(M == (3 * P)); + } + SECTION("evaluation") + { + Polynomial<2> P({2, -3, 4}); + double result = P.evaluate(3); + REQUIRE(result == 29); + result = P(3); + REQUIRE(result == 29); + } + SECTION("primitive") + { + Polynomial<2> P({2, -3, 4}); + TinyVector<4> coefs = zero; + Polynomial<3> Q(coefs); + Q = primitive(P); + Polynomial<3> R({0, 2, -3. / 2, 4. / 3}); + REQUIRE(Q == R); + } +} -- GitLab