1#ifndef TATOOINE_POLYNOMIAL_H
2#define TATOOINE_POLYNOMIAL_H
13template <
typename Real, std::
size_t Degree>
24 static constexpr std::size_t
degree() {
return Degree; }
46 constexpr polynomial(std::array<Real, Degree + 1>
const& coeffs)
47 : m_coefficients{coeffs} {}
49 template <
typename OtherReal, std::
size_t OtherDegree>
50 requires(OtherDegree <= Degree)
52 : m_coefficients{make_array<Degree + 1>(Real(0))} {
53 for (std::size_t i = 0; i < OtherDegree + 1; ++i) {
58 constexpr polynomial(std::array<Real, Degree + 1>&& coeffs)
59 : m_coefficients{std::move(coeffs)} {}
63 sizeof...(coeffs) == Degree + 1)
65 : m_coefficients{
static_cast<Real
>(coeffs)...} {}
67 template <arithmetic OtherReal>
69 : m_coefficients{
make_array<Real>(coeffs.data())} {
72 template <arithmetic OtherReal>
73 constexpr polynomial(std::array<OtherReal, Degree + 1>
const& coeffs)
85 for (std::size_t i = 0; i < Degree + 1; ++i) {
86 y += acc * m_coefficients[i];
87 acc *=
static_cast<Real
>(x);
95 auto c(std::size_t i)
const ->
auto const& {
return m_coefficients[i]; }
96 auto c(std::size_t i) ->
auto& {
return m_coefficients[i]; }
98 auto coefficient(std::size_t i)
const ->
auto const& {
return m_coefficients[i]; }
99 auto coefficient(std::size_t i) ->
auto const& {
return m_coefficients[i]; }
106 m_coefficients = coeffs;
111 m_coefficients = std::move(coeffs);
114 template <arithmetic OtherReal>
116 std::array<OtherReal, Degree + 1>
const& coeffs) ->
void {
117 m_coefficients = make_array<Real>(coeffs);
122 ->
void requires(
sizeof...(coeffs) == Degree + 1) {
123 m_coefficients = std::array<Real, Degree + 1>{
static_cast<Real
>(coeffs)...};
127 template <std::size_t... Is>
128 constexpr auto diff(std::index_sequence<Is...> )
const {
129 return polynomial<Real, Degree - 1>{(m_coefficients[Is + 1] * (Is + 1))...};
134 if constexpr (Degree >= 1) {
135 return diff(std::make_index_sequence<Degree>{});
140 auto print(std::ostream& out, std::string
const& x)
const -> std::ostream& {
146 }
else if (c(1) == -1) {
149 out <<
" + " << c(1) <<
" * " << x;
153 for (std::size_t i = 2; i < Degree + 1; ++i) {
156 out <<
" + " << x <<
"^" << i;
157 }
else if (c(i) == -1) {
158 out <<
" - " << x <<
"^" << i;
160 out <<
" + " << c(i) <<
" * " << x <<
"^" << i;
170template <
typename... Coeffs>
173template <
typename Real, std::
size_t N>
178template <
typename Real, std::
size_t Degree>
186template <
typename Real>
191 return {-p.c(0) / p.c(1)};
195template <
typename Real>
197 auto const a = p.c(0);
198 auto const b = p.c(1);
199 auto const c = p.c(2);
204 auto const discr = b * b - 4 * a * c;
207 }
else if (std::abs(discr) < 1e-10) {
208 return {-b / (2 * c)};
210 std::vector<Real> solutions;
211 solutions.reserve(2);
213 (b > 0) ? -0.5 * (b + std::sqrt(discr)) : -0.5 * (b - std::sqrt(discr));
214 solutions.push_back(q / c);
215 solutions.push_back(a / q);
216 std::swap(solutions[0], solutions[1]);
223template <
typename Real>
228 std::vector<Real> solutions;
241 p = Real(1) / 3 * (-Real(1) / 3 * sq_A + B);
242 q = Real(1) / 2 * (Real(2) / 27 * A * sq_A - Real(1) / 3 * A * B + C);
248 constexpr Real eps = 1e-30;
249 constexpr auto is_zero = [](
auto const x) {
250 return ((x) > -eps && (x) < eps);
256 Real u = std::cbrt(-q);
257 solutions = {2 * u, -u};
260 Real phi = Real(1) / 3 * std::acos(-q / std::sqrt(-cb_p));
261 Real t = 2 * std::sqrt(-p);
263 solutions = {t * std::cos(phi), -t * std::cos(phi + M_PI / 3),
264 -t * std::cos(phi - M_PI / 3)};
266 Real sqrt_D = std::sqrt(D);
267 Real u = std::cbrt(sqrt_D - q);
268 Real v = -std::cbrt(sqrt_D + q);
274 sub = Real(1) / 3 * A;
276 for (
auto& s : solutions) {
280 std::sort(
begin(solutions),
end(solutions));
287template <
typename Real>
293 std::vector<Real> solutions;
296 auto const A = f.c(3) / f.c(4);
297 auto const B = f.c(2) / f.c(4);
298 auto const C = f.c(1) / f.c(4);
299 auto const D = f.c(0) / f.c(4);
302 auto const sq_A = A * A;
303 auto const p = -Real(3) / 8 * sq_A + B;
304 auto const q = Real(1) / 8 * sq_A * A - Real(1) / 2 * A * B + C;
305 auto const r = -Real(3) / 256 * sq_A * sq_A + Real(1) / 16 * sq_A * B -
306 Real(1) / 4 * A * C + D;
308 constexpr Real eps = 0;
309 constexpr auto is_zero = [](
auto const x) {
310 return ((x) > -eps && (x) < eps);
315 if (std::find(
begin(solutions),
end(solutions), 0) ==
end(solutions)) {
316 solutions.push_back(0);
320 auto const z =
solve(
polynomial{Real(1) / 2 * r * p - Real(1) / 8 * q * q,
321 -r, -Real(1) / 2 * p, 1})
346 auto const other_solutions =
solve(
polynomial{z + u, q < 0 ? v : -v, 1});
347 std::copy(
begin(other_solutions),
end(other_solutions),
348 std::back_inserter(solutions));
352 auto const sub = Real(1) / 4 * A;
354 for (
auto& s : solutions) {
358 std::sort(
begin(solutions),
end(solutions));
359 solutions.erase(std::unique(
begin(solutions),
end(solutions)),
366template <
typename Real, std::
size_t Degree>
368 return f.
print(out,
"x");
376template <
typename Real, std::
size_t Degree>
Definition: concepts.h:33
Definition: algorithm.h:6
auto operator<<(std::ostream &out, linspace< Real > const &l) -> auto &
Definition: linspace.h:165
typename common_type_impl< Ts... >::type common_type
Definition: common_type.h:23
auto begin(Range &&range)
Definition: iterator_facade.h:318
auto end(Range &&range)
Definition: iterator_facade.h:322
constexpr auto make_array()
Definition: make_array.h:22
auto solve(polynomial< Real, 1 > const &p) -> std::vector< Real >
solve a + b*x
Definition: polynomial.h:187
static constexpr bool is_polynomial
Definition: polynomial.h:380
constexpr auto diff(polynomial< Real, Degree > const &f)
Definition: polynomial.h:179
Definition: polynomial.h:374
Definition: polynomial.h:14
constexpr auto diff() const
Definition: polynomial.h:133
constexpr auto set_coefficients(std::array< Real, Degree+1 > &&coeffs) -> void
Definition: polynomial.h:109
constexpr polynomial(polynomial< OtherReal, OtherDegree > const &other)
Definition: polynomial.h:51
constexpr polynomial(tensor< OtherReal, Degree+1 > const &coeffs)
Definition: polynomial.h:68
constexpr polynomial(polynomial const &other)=default
auto print(std::ostream &out, std::string const &x) const -> std::ostream &
Definition: polynomial.h:140
Real real_type
Definition: polynomial.h:19
constexpr polynomial(std::array< Real, Degree+1 > &&coeffs)
Definition: polynomial.h:58
constexpr polynomial(arithmetic auto const ... coeffs)
Definition: polynomial.h:62
auto coefficient(std::size_t i) -> auto const &
Definition: polynomial.h:99
constexpr polynomial(polynomial &&other) noexcept=default
auto coefficient(std::size_t i) const -> auto const &
Definition: polynomial.h:98
auto coefficients() -> auto const &
Definition: polynomial.h:102
constexpr polynomial()
Definition: polynomial.h:35
static constexpr std::size_t degree()
Definition: polynomial.h:24
constexpr auto set_coefficients(arithmetic auto const ... coeffs) -> void requires(sizeof...(coeffs)==Degree+1)
Definition: polynomial.h:121
auto c(std::size_t i) const -> auto const &
Definition: polynomial.h:95
constexpr polynomial(std::array< OtherReal, Degree+1 > const &coeffs)
Definition: polynomial.h:73
auto c(std::size_t i) -> auto &
Definition: polynomial.h:96
constexpr auto set_coefficients(std::array< Real, Degree+1 > const &coeffs) -> void
Definition: polynomial.h:104
constexpr polynomial(std::array< Real, Degree+1 > const &coeffs)
Definition: polynomial.h:46
constexpr auto set_coefficients(std::array< OtherReal, Degree+1 > const &coeffs) -> void
Definition: polynomial.h:115
constexpr auto diff(std::index_sequence< Is... >) const
Definition: polynomial.h:128
constexpr auto operator=(polynomial &&other) noexcept -> polynomial &=default
std::array< Real, Degree+1 > m_coefficients
Definition: polynomial.h:29
constexpr auto operator=(polynomial const &other) -> polynomial &=default
constexpr auto operator()(arithmetic auto const x) const
evaluates c0 * x^0 + c1 * x^1 + ... + c{N-1} * x^{N-1}
Definition: polynomial.h:93
auto coefficients() const -> auto const &
Definition: polynomial.h:101
constexpr auto evaluate(arithmetic auto const x) const
evaluates c0 * x^0 + c1 * x^1 + ... + c{N-1} * x^{N-1}
Definition: polynomial.h:82