Select Git revision
Polynomial1D.hpp
-
Stéphane Del Pino authored
- Remains lots of work in 2d and 3d (great progresses in 2d) - Remains to improve some constants evaluations (for Mie-Grunisen) - The case Gamma_infty<1 is not started
Stéphane Del Pino authored- Remains lots of work in 2d and 3d (great progresses in 2d) - Remains to improve some constants evaluations (for Mie-Grunisen) - The case Gamma_infty<1 is not started
Polynomial1D.hpp 8.53 KiB
#ifndef POLYNOMIAL_1D_HPP
#define POLYNOMIAL_1D_HPP
#include <utils/Array.hpp>
#include <utils/Exceptions.hpp>
#include <algorithm>
class [[nodiscard]] Polynomial1D
{
private:
std::vector<double> m_coefficients;
PUGS_INLINE
size_t _getRealDegree() const
{
size_t real_degree = this->degree();
while (real_degree > 0 and std::abs(m_coefficients[real_degree]) < 1E-14) {
--real_degree;
}
return real_degree;
}
PUGS_INLINE
friend Polynomial1D _simplify(Polynomial1D && p)
{
// return std::move(p);
size_t real_degree = p._getRealDegree();
if (real_degree != p.degree()) {
Polynomial1D q(real_degree);
for (size_t i = 0; i <= real_degree; ++i) {
q.coefficient(i) = p.coefficient(i);
}
return q;
} else {
return std::move(p);
}
}
public:
friend std::ostream& operator<<(std::ostream& os, const Polynomial1D& p)
{
bool has_written = false;
for (size_t i = 0; i < p.m_coefficients.size(); ++i) {
const double& coef = p.m_coefficients[i];
// if (coef != 0) {
if (coef > 0) {
if (has_written) {
os << " + ";
}
os << coef;
} else {
if (has_written) {
os << " - " << -coef;
} else {
os << coef;
}
}
if (i > 0) {
os << "*x";
if (i > 1) {
os << '^' << i;
}
}
has_written = true;
// }
}
if (not has_written) {
os << 0;
}
return os;
}
PUGS_INLINE
Polynomial1D operator-() const
{
Polynomial1D opposite(this->degree());
for (size_t i = 0; i < m_coefficients.size(); ++i) {
opposite.m_coefficients[i] = -m_coefficients[i];
}
return _simplify(std::move(opposite));
}
PUGS_INLINE
friend Polynomial1D operator*(const double a, const Polynomial1D& p)
{
Polynomial1D product(p.degree());
for (size_t i = 0; i < p.m_coefficients.size(); ++i) {
product.m_coefficients[i] = a * p.m_coefficients[i];
}
return _simplify(std::move(product));
}
PUGS_INLINE
Polynomial1D operator*(const Polynomial1D& p) const
{
Polynomial1D product(this->degree() + p.degree());
std::fill(begin(product.m_coefficients), end(product.m_coefficients), 0);
for (size_t i = 0; i < this->m_coefficients.size(); ++i) {
for (size_t j = 0; j < p.m_coefficients.size(); ++j) {
product.m_coefficients[i + j] += this->m_coefficients[i] * p.m_coefficients[j];
}
}
return _simplify(std::move(product));
}
PUGS_INLINE
Polynomial1D operator+(const Polynomial1D& p) const
{
auto sum_left_is_bigger = [](const Polynomial1D& greater, const Polynomial1D& smaller) {
Polynomial1D result(greater.degree());
for (size_t i = 0; i < greater.m_coefficients.size(); ++i) {
result.m_coefficients[i] = greater.m_coefficients[i];
}
for (size_t i = 0; i < smaller.m_coefficients.size(); ++i) {
result.m_coefficients[i] += smaller.m_coefficients[i];
}
return _simplify(std::move(result));
};
if (m_coefficients.size() >= p.m_coefficients.size()) {
return sum_left_is_bigger(*this, p);
} else {
return sum_left_is_bigger(p, *this);
}
}
PUGS_INLINE
Polynomial1D operator-(const Polynomial1D& p) const
{
if (m_coefficients.size() >= p.m_coefficients.size()) {
Polynomial1D result(this->degree());
for (size_t i = 0; i < p.m_coefficients.size(); ++i) {
result.m_coefficients[i] = m_coefficients[i] - p.m_coefficients[i];
}
for (size_t i = p.m_coefficients.size(); i < m_coefficients.size(); ++i) {
result.m_coefficients[i] = m_coefficients[i];
}
return _simplify(std::move(result));
} else {
Polynomial1D result(p.degree());
for (size_t i = 0; i < m_coefficients.size(); ++i) {
result.m_coefficients[i] = m_coefficients[i] - p.m_coefficients[i];
}
for (size_t i = m_coefficients.size(); i < p.m_coefficients.size(); ++i) {
result.m_coefficients[i] = -p.m_coefficients[i];
}
return _simplify(std::move(result));
}
}
PUGS_INLINE
Polynomial1D operator%(const Polynomial1D& q) const
{
const Polynomial1D& p = *this;
Polynomial1D ratio(this->degree());
std::fill(begin(ratio.m_coefficients), end(ratio.m_coefficients), 0);
Polynomial1D remaining(this->degree());
for (size_t i = 0; i < m_coefficients.size(); ++i) {
remaining.m_coefficients[i] = m_coefficients[i];
}
const size_t p_degree = p.degree();
const size_t q_degree = q._getRealDegree();
for (ssize_t i = p_degree - q_degree; i >= 0; --i) {
ratio.m_coefficients[i] = remaining.m_coefficients[q_degree + i] / q.m_coefficients[q_degree];
for (ssize_t j = q_degree + i; j >= i; --j) {
remaining.m_coefficients[j] -= ratio.m_coefficients[i] * q.m_coefficients[j - i];
}
}
if (q_degree == 0) {
remaining.m_coefficients.resize(1);
remaining.m_coefficients[0] = 0;
} else {
remaining.m_coefficients.resize(std::max(q_degree - 1, 1ul));
}
// for (size_t j = q_degree; j <= remaining.degree(); ++j) {
// remaining.m_coefficients[j] = 0;
// }
return _simplify(std::move(remaining));
}
PUGS_INLINE
Polynomial1D operator/(const Polynomial1D& q) const
{
const Polynomial1D& p = *this;
Polynomial1D ratio(this->degree());
std::fill(begin(ratio.m_coefficients), end(ratio.m_coefficients), 0);
Polynomial1D remaining(this->degree());
for (size_t i = 0; i < m_coefficients.size(); ++i) {
remaining.m_coefficients[i] = m_coefficients[i];
}
const size_t p_degree = p.degree();
const size_t q_degree = q._getRealDegree();
for (ssize_t i = p_degree - q_degree; i >= 0; --i) {
ratio.m_coefficients[i] = remaining.m_coefficients[q_degree + i] / q.m_coefficients[q_degree];
for (ssize_t j = q_degree + i; j >= i; --j) {
remaining.m_coefficients[j] -= ratio.m_coefficients[i] * q.m_coefficients[j - i];
}
}
return _simplify(std::move(ratio));
}
PUGS_INLINE size_t degree() const
{
Assert(m_coefficients.size() > 0);
return m_coefficients.size() - 1;
}
PUGS_INLINE
double& coefficient(const size_t i)
{
Assert(i < m_coefficients.size(), "invalid coefficient number");
return m_coefficients[i];
}
PUGS_INLINE
const double& coefficient(const size_t i) const
{
Assert(i < m_coefficients.size(), "invalid coefficient number");
return m_coefficients[i];
}
PUGS_INLINE
friend Polynomial1D derive(const Polynomial1D& p)
{
if (p.degree() > 0) {
Polynomial1D derivative{p.degree() - 1};
for (size_t i = 0; i <= derivative.degree(); ++i) {
derivative.m_coefficients[i] = (i + 1) * p.m_coefficients[i + 1];
}
return derivative;
} else {
return Polynomial1D(std::vector<double>{0});
}
}
PUGS_INLINE
friend Polynomial1D primitive(const Polynomial1D& p)
{
if (p.degree() > 0) {
Polynomial1D primitive{p.degree() + 1};
primitive.m_coefficients[0] = 0;
for (size_t i = 0; i <= p.degree(); ++i) {
primitive.m_coefficients[i + 1] = p.m_coefficients[i] / (i + 1);
}
return _simplify(std::move(primitive));
} else {
return Polynomial1D(std::vector<double>{0});
}
}
PUGS_INLINE
double operator()(const double x) const
{
double value = m_coefficients[this->degree()];
for (ssize_t i = this->degree() - 1; i >= 0; --i) {
value *= x;
value += m_coefficients[i];
}
return value;
}
Polynomial1D& operator=(Polynomial1D&&) = default;
Polynomial1D& operator=(const Polynomial1D&) = default;
PUGS_INLINE
explicit Polynomial1D(const std::vector<double>& coeffients) : m_coefficients(coeffients.size())
{
Assert(coeffients.size() > 0, "empty list is not allowed");
for (size_t i = 0; i < coeffients.size(); ++i) {
m_coefficients[i] = coeffients[i];
}
size_t real_degree = this->_getRealDegree();
if (real_degree + 1 < m_coefficients.size()) {
std::vector<double> real_coefficients(real_degree + 1);
for (size_t i = 0; i <= real_degree; ++i) {
real_coefficients[i] = m_coefficients[i];
}
m_coefficients = std::move(real_coefficients);
}
}
PUGS_INLINE
explicit Polynomial1D(const size_t degree) : m_coefficients(degree + 1)
{
std::fill(m_coefficients.begin(), m_coefficients.end(), 0);
}
Polynomial1D(const Polynomial1D&) = default;
Polynomial1D(Polynomial1D &&) = default;
~Polynomial1D() = default;
};
#endif // POLYNOMIAL_1D_HPP