Skip to content
Snippets Groups Projects
Commit 613205e9 authored by Emmanuel Labourasse's avatar Emmanuel Labourasse
Browse files

Add a class for Taylor polynomials

parent 84c04b9e
No related branches found
No related tags found
No related merge requests found
#ifndef TAYLOR_POLYNOMIAL_HPP
#define TAULOR_POLYNOMIAL_HPP
#include <algebra/TinyVector.hpp>
#include <analysis/CubeGaussQuadrature.hpp>
#include <analysis/GaussQuadratureDescriptor.hpp>
#include <analysis/QuadratureManager.hpp>
#include <analysis/SquareGaussQuadrature.hpp>
#include <analysis/TriangleGaussQuadrature.hpp>
#include <geometry/SquareTransformation.hpp>
#include <geometry/TriangleTransformation.hpp>
#include <utils/Exceptions.hpp>
template <size_t N, size_t Dimension>
class TaylorPolynomial
{
private:
static constexpr size_t size_coef = [] {
if constexpr (Dimension == 1) {
return N + 1;
} else if constexpr (Dimension == 2) {
return (N + 1) * (N + 2) / 2;
} else {
static_assert(Dimension == 3);
return (N + 1) * (N + 2) * (N + 3) / 6;
}
}();
using Coefficients = TinyVector<size_coef, double>;
Coefficients m_coefficients;
TinyVector<Dimension> m_x0;
static_assert((N >= 0), "TaylorPolynomial degree must be non-negative");
static_assert((Dimension > 0), "TaylorPolynomial dimension must be positive");
static_assert((Dimension <= 3), "TaylorPolynomial dimension must no greater than three");
public:
PUGS_INLINE
constexpr size_t
degree() const
{
return N;
}
constexpr size_t
dim() const
{
return Dimension;
}
PUGS_INLINE
constexpr const TinyVector<size_coef, double>&
coefficients() const
{
return m_coefficients;
}
PUGS_INLINE
constexpr const TinyVector<Dimension, double>&
x0() const
{
return m_x0;
}
PUGS_INLINE
constexpr TinyVector<size_coef, double>&
coefficients()
{
return m_coefficients;
}
PUGS_INLINE constexpr bool
operator==(const TaylorPolynomial& q) const
{
return (m_coefficients == q.m_coefficients && m_x0 = q.m_x0);
}
PUGS_INLINE constexpr TaylorPolynomial(const TinyVector<size_coef, double>& coefficients,
const TinyVector<Dimension, double>& x0) noexcept
: m_coefficients{coefficients}, m_x0(x0)
{}
PUGS_INLINE
constexpr TaylorPolynomial(TinyVector<size_coef, double>&& coefficients,
const TinyVector<Dimension, double>&& x0) noexcept
: m_coefficients{coefficients}, m_x0(x0)
{}
PUGS_INLINE
constexpr bool
operator!=(const TaylorPolynomial& q) const
{
return not this->operator==(q);
}
PUGS_INLINE constexpr TaylorPolynomial
operator+(const TaylorPolynomial Q) const
{
Assert(m_x0 == Q.m_x0, "You cannot add Taylor polynomials with different origins");
TaylorPolynomial<N, Dimension> P(m_coefficients);
for (size_t i = 0; i < size_coef; ++i) {
P.coefficients()[i] += Q.coefficients()[i];
}
return P;
}
PUGS_INLINE constexpr TaylorPolynomial
operator-() const
{
TaylorPolynomial<N, Dimension> P;
P.coefficients() = -coefficients();
return P;
}
PUGS_INLINE constexpr TaylorPolynomial
operator-(const TaylorPolynomial Q) const
{
Assert(m_x0 == Q.m_x0, "You cannot subtract Taylor polynomials with different origins");
TaylorPolynomial<N, Dimension> P(m_coefficients);
P = P + (-Q);
return P;
}
template <size_t M, size_t Dim>
PUGS_INLINE constexpr TaylorPolynomial&
operator=(const TaylorPolynomial<M, Dim>& Q)
{
coefficients() = zero;
for (size_t i = 0; i < size_coef; ++i) {
coefficients()[i] = Q.coefficients()[i];
}
m_x0 = Q.m_x0;
return *this;
}
PUGS_INLINE constexpr TaylorPolynomial&
operator+=(const TaylorPolynomial& Q)
{
Assert(m_x0 == Q.m_x0, "You cannot add Taylor polynomials with different origins");
m_coefficients += Q.coefficients();
return *this;
}
template <size_t M>
PUGS_INLINE constexpr TaylorPolynomial&
operator-=(const TaylorPolynomial& Q)
{
Assert(m_x0 == Q.m_x0, "You cannot subtract Taylor polynomials with different origins");
m_coefficients -= Q.coefficients();
return *this;
}
PUGS_INLINE
constexpr TaylorPolynomial
operator*(const double& lambda) const
{
TinyVector<size_coef> mult_coefs = lambda * m_coefficients;
TaylorPolynomial<N, Dimension> M(mult_coefs);
return M;
}
PUGS_INLINE
constexpr friend TaylorPolynomial<N, Dimension>
operator*(const double& lambda, const TaylorPolynomial<N, Dimension> P)
{
return P * lambda;
}
PUGS_INLINE
constexpr double
operator[](const TinyVector<Dimension, size_t> relative_pos) const
{
size_t total_degree = 0;
for (size_t i = 0; i < Dimension; ++i) {
Assert((relative_pos[i] <= N),
"You are looking for a coefficient of order greater than the degree of the polynomial");
total_degree += relative_pos[i];
}
Assert((total_degree <= N), "The sum of the degrees of the coefficient you are looking for is greater than the "
"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 NotImplementedError("Not yet Available in 3D");
static_assert(Dimension == 3);
size_t total_degree = relative_pos[0] + relative_pos[1] + relative_pos[2];
size_t total_sub_degree = relative_pos[1] + relative_pos[2];
return total_degree * (total_degree + 1) * (total_degree + 2) / 6 +
total_sub_degree * (total_sub_degree + 1) / 2 + relative_pos[2];
}
return absolute_coefs[absolute_position];
}
PUGS_INLINE
constexpr double
operator[](const TinyVector<Dimension, size_t> relative_pos)
{
size_t total_degree = 0;
for (size_t i = 0; i < Dimension; ++i) {
Assert((relative_pos[i] <= N),
"You are looking for a coefficient of order greater than the degree of the polynomial");
total_degree += relative_pos[i];
}
Assert((total_degree <= N), "The sum of the degrees of the coefficient you are looking for is greater than the "
"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 NotImplementedError("Not yet Available in 3D");
static_assert(Dimension == 3);
size_t total_degree = relative_pos[0] + relative_pos[1] + relative_pos[2];
size_t total_sub_degree = relative_pos[1] + relative_pos[2];
absolute_position = total_degree * (total_degree + 1) * (total_degree + 2) / 6 +
total_sub_degree * (total_sub_degree + 1) / 2 + relative_pos[2];
}
return absolute_coefs[absolute_position];
}
PUGS_INLINE
constexpr double
absolute_position(const TinyVector<Dimension, size_t> relative_pos) const
{
size_t total_degree = 0;
for (size_t i = 0; i < Dimension; ++i) {
Assert((relative_pos[i] <= N),
"You are looking for a coefficient of order greater than the degree of the polynomial");
total_degree += relative_pos[i];
}
Assert((total_degree <= N), "The sum of the degrees of the coefficient you are looking for is greater than the "
"degree of the polynomial");
size_t abs_pos = 0;
if constexpr (Dimension == 1) {
abs_pos = relative_pos[0];
} else if constexpr (Dimension == 2) {
abs_pos = total_degree * (total_degree + 1) / 2 + relative_pos[1];
} else {
static_assert(Dimension == 3);
size_t total_degree = relative_pos[0] + relative_pos[1] + relative_pos[2];
size_t total_sub_degree = relative_pos[1] + relative_pos[2];
abs_pos = total_degree * (total_degree + 1) * (total_degree + 2) / 6 +
total_sub_degree * (total_sub_degree + 1) / 2 + relative_pos[2];
// throw NotImplementedError("Not yet Available in 3D");
}
return abs_pos;
}
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 - m_x0;
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] - m_x0[1]);
relative_pos = TinyVector<Dimension, 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] - m_x0[0]);
relative_pos = TinyVector<Dimension, size_t>(j - 1, i - 1);
valuex += P[relative_pos];
}
value += valuex;
}
} else {
throw NotImplementedError("Not yet Available in 3D");
}
return value;
}
PUGS_INLINE size_t
find_size_coef(const size_t degree)
{
if constexpr (Dimension == 1) {
return degree + 1;
} else if constexpr (Dimension == 2) {
return (degree + 1) * (degree + 2) / 2;
} else {
static_assert(Dimension == 3);
return (degree + 1) * (degree + 2) * (degree + 3) / 6;
}
}
PUGS_INLINE constexpr TaylorPolynomial<N, Dimension>
derivative(const size_t var) const
{
const auto P = *this;
TinyVector<size_coef> coefs(zero);
TaylorPolynomial<N, Dimension> Q(coefs);
if constexpr (N != 0) {
Assert(var < Dimension,
"You can not derive a polynomial with respect to a variable of rank greater than the dimension");
if constexpr (Dimension == 1) {
for (size_t i = 0; i < size_coef - 1; ++i) {
coefs[i] = double(i + 1) * P.coefficients()[i + 1];
}
} else if constexpr (Dimension == 2) {
if (var == 0) {
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < N - i; ++j) {
TinyVector<Dimension, size_t> relative_pos(i, j);
TinyVector<Dimension, size_t> relative_posp(i + 1, j);
size_t absolute_position = Q.absolute_position(relative_pos);
size_t absolute_positionp = P.absolute_position(relative_posp);
Q.coefficients()[absolute_position] = double(i + 1) * m_coefficients[absolute_positionp];
}
}
} else {
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < N - i; ++j) {
TinyVector<Dimension, size_t> relative_pos(i, j);
TinyVector<Dimension, size_t> relative_posp(i, j + 1);
size_t absolute_position = Q.absolute_position(relative_pos);
size_t absolute_positionp = P.absolute_position(relative_posp);
Q.coefficients()[absolute_position] = double(j + 1) * m_coefficients[absolute_positionp];
}
}
}
} else {
static_assert(Dimension == 3);
if (var == 0) {
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < N - i; ++j) {
for (size_t k = 0; k < N - i - j; ++k) {
TinyVector<Dimension, size_t> relative_pos(i, j, k);
TinyVector<Dimension, size_t> relative_posp(i + 1, j, k);
size_t absolute_position = Q.absolute_position(relative_pos);
size_t absolute_positionp = P.absolute_position(relative_posp);
Q.coefficients()[absolute_position] = double(i + 1) * m_coefficients[absolute_positionp];
}
}
}
} else if (var == 1) {
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < N - i; ++j) {
for (size_t k = 0; k < N - i - j; ++k) {
TinyVector<Dimension, size_t> relative_pos(i, j, k);
TinyVector<Dimension, size_t> relative_posp(i, j + 1, k);
size_t absolute_position = Q.absolute_position(relative_pos);
size_t absolute_positionp = P.absolute_position(relative_posp);
Q.coefficients()[absolute_position] = double(j + 1) * m_coefficients[absolute_positionp];
}
}
}
} else {
for (size_t i = 0; i < N; ++i) {
for (size_t j = 0; j < N - i; ++j) {
for (size_t k = 0; k < N - i - j; ++k) {
TinyVector<Dimension, size_t> relative_pos(i, j, k);
TinyVector<Dimension, size_t> relative_posp(i, j, k + 1);
size_t absolute_position = Q.absolute_position(relative_pos);
size_t absolute_positionp = P.absolute_position(relative_posp);
Q.coefficients()[absolute_position] = double(k + 1) * m_coefficients[absolute_positionp];
}
}
}
}
// throw NotImplementedError("Not yet Available in 3D");
}
}
return Q;
}
PUGS_INLINE
constexpr friend std::ostream&
operator<<(std::ostream& os, const TaylorPolynomial<N, Dimension>& P)
{
// os << "P(x) = ";
bool all_coef_zero = true;
if (N == 0) {
os << P.coefficients()[0];
return os;
}
if constexpr (Dimension == 1) {
if (N != 1) {
if (P.coefficients()[N] != 0.) {
if (P.coefficients()[N] < 0.) {
os << "- ";
}
if (P.coefficients()[N] != 1 && P.coefficients()[N] != -1) {
os << std::abs(P.coefficients()[N]);
}
os << "(x - " << P.x0()[0] << ")"
<< "^" << N;
all_coef_zero = false;
}
}
for (size_t i = N - 1; i > 1; --i) {
if (P.coefficients()[i] != 0.) {
if (P.coefficients()[i] > 0.) {
os << " + ";
} else if (P.coefficients()[i] < 0.) {
os << " - ";
}
if (P.coefficients()[i] != 1 && P.coefficients()[i] != -1) {
os << std::abs(P.coefficients()[i]);
}
os << "(x - " << P.x0()[0] << ")"
<< "^" << i;
all_coef_zero = false;
}
}
if (P.coefficients()[1] != 0.) {
if (P.coefficients()[1] > 0. && N != 1) {
os << " + ";
} else if (P.coefficients()[1] < 0.) {
os << " - ";
}
if (P.coefficients()[1] != 1 && P.coefficients()[1] != -1) {
os << std::abs(P.coefficients()[1]);
}
os << "(x - " << P.x0()[0] << ")";
all_coef_zero = false;
}
if (P.coefficients()[0] != 0. || all_coef_zero) {
if (P.coefficients()[0] > 0.) {
os << " + ";
} else if (P.coefficients()[0] < 0.) {
os << " - ";
}
os << std::abs(P.coefficients()[0]);
}
return os;
} else if constexpr (Dimension == 2) {
size_t i = 0;
size_t j = N;
TinyVector<Dimension, size_t> rel_pos(i, j);
double coef = P[rel_pos];
if (coef != 0.) {
if (coef < 0.) {
os << " - ";
}
if (coef != 1 && coef != -1) {
os << std::abs(coef);
}
os << "(y - " << P.x0()[1] << ")"
<< "^" << N;
}
size_t degree = N;
for (size_t k = size_coef - 1; k > 0; --k) {
if (j > 0) {
j--;
i++;
} else {
degree--;
j = degree;
i = 0;
}
rel_pos = TinyVector<Dimension, size_t>(i, j);
double coef = P[rel_pos];
if (coef != 0.) {
if (coef > 0.) {
os << " + ";
} else if (coef < 0.) {
os << " - ";
}
if ((coef != 1 && coef != -1) || (i == 0 && j == 0)) {
os << std::abs(coef);
}
if (i == 0 && j == 0)
continue;
if (i == 0) {
if (j != 1) {
os << "(y - " << P.x0()[1] << ")"
<< "^" << j;
} else {
os << "y";
}
} else if (j == 0) {
if (i == 1) {
os << "(x - " << P.x0()[0] << ")";
} else {
os << "(x - " << P.x0()[0] << ")"
<< "^" << i;
}
} else {
if (i == 1 && j == 1) {
os << "(x - " << P.x0()[0] << ")"
<< "(y - " << P.x0()[1] << ")";
} else if (i == 1) {
os << "(x - " << P.x0()[0] << ")"
<< "(y - " << P.x0()[1] << ")^" << j;
} else if (j == 1) {
os << "(x - " << P.x0()[0] << ")"
<< "^i"
<< "(y - " << P.x0()[1] << ")";
} else {
os << "(x - " << P.x0()[0] << ")"
<< "^i"
<< "(y - " << P.x0()[1] << ")^" << j;
}
}
all_coef_zero = false;
}
}
return os;
} else {
// size_t i = 0;
// size_t j = 0;
// size_t k = N;
// TinyVector<Dimension, size_t> rel_pos(i, j, k);
// double coef = P[rel_pos];
// if (coef != 0.) {
// if (coef < 0.) {
// os << " - ";
// }
// if (coef != 1 && coef != -1) {
// os << std::abs(coef);
// }
// os << "z^" << N;
// }
// size_t degree = N;
// for (size_t l = size_coef - 1; l > 0; --l) {
// if (k > 0) {
// k--;
// if (j < k) {
// j++;
// } else {
// j--;
// i++;
// }
// } else {
// degree--;
// k = degree;
// i = 0;
// j = 0;
// }
// rel_pos = TinyVector<Dimension, size_t>(i, j, k);
// double coef = P[rel_pos];
// if (coef != 0.) {
// if (coef > 0.) {
// os << " + ";
// } else if (coef < 0.) {
// os << " - ";
// }
// if ((coef != 1 && coef != -1) || (i == 0 && j == 0 && k == 0)) {
// os << std::abs(coef);
// }
// if (i == 0 && j == 0 && k == 0)
// continue;
// if (i == 0 && j == 0) {
// if (k != 1) {
// os << "z^" << j;
// } else {
// os << "z";
// }
// } else if (i == 0 && k == 0) {
// if (j == 1) {
// os << "y";
// } else {
// os << "y^" << i;
// }
// } else if (j == 0 && k == 0) {
// if (i == 1) {
// os << "x";
// } else {
// os << "x^" << i;
// }
// } else {
// if (i == 1 && j == 1 && k == 1) {
// os << "xyz";
// } else if (i == 1) {
// os << "x"
// << "y^" << j << "z^" << k;
// } else if (j == 1) {
// os << "x^" << i << "y"
// << "z^" << k;
// } else if (k == 1) {
// os << "x^" << i << "y^" << j << "z";
// } else {
// os << "x^" << i << "y^" << j << "z^" << k;
// }
// }
// all_coef_zero = false;
// }
//
for (size_t l = 0; l < size_coef; ++l) {
double coef = P.coefficients()[l];
os << coef << " ";
}
return os;
// throw NotImplementedError("Not yet Available in 3D");
}
}
PUGS_INLINE constexpr TaylorPolynomial() noexcept = default;
~TaylorPolynomial() = default;
};
template <size_t N, size_t Dimension, size_t P>
PUGS_INLINE double
integrate(const TaylorPolynomial<N, Dimension> Q, const std::array<TinyVector<Dimension>, P>& positions)
{
double integral = 0.;
static_assert(P > 1, "For the integration, number of positions should be greater or equal to 2");
static_assert(N >= 0, "invalid degree");
if constexpr (Dimension == 1) {
static_assert(P == 2, "In 1D number of positions should be 2");
throw NotImplementedError("Not yet Available in 1D");
} else if constexpr (Dimension == 2) {
static_assert(P <= 4, "In 2D number of positions should be lesser or equal to 4");
if constexpr (P == 2) {
} else if constexpr (P == 3) {
const QuadratureFormula<2>& lN = QuadratureManager::instance().getTriangleFormula(GaussQuadratureDescriptor(N));
auto point_list = lN.pointList();
auto weight_list = lN.weightList();
TriangleTransformation<2> t{positions[0], positions[1], positions[2]};
auto value = weight_list[0] * Q(t(point_list[0]));
for (size_t i = 1; i < weight_list.size(); ++i) {
value += weight_list[i] * Q(t(point_list[i]));
}
integral = value;
} else {
const QuadratureFormula<2>& lN = QuadratureManager::instance().getSquareFormula(GaussQuadratureDescriptor(N));
auto point_list = lN.pointList();
auto weight_list = lN.weightList();
SquareTransformation<2> s{positions[0], positions[1], positions[2], positions[3]};
auto value = weight_list[0] * Q(s(point_list[0]));
for (size_t i = 1; i < weight_list.size(); ++i) {
value += weight_list[i] * Q(s(point_list[i]));
}
integral = value;
}
} else {
static_assert(Dimension == 3, "Dimension should be <=3");
throw NotImplementedError("Not yet Available in 3D");
}
return integral;
}
#endif // POLYNOMIALP_HPP
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment