123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598 |
- // David Eberly, Geometric Tools, Redmond WA 98052
- // Copyright (c) 1998-2020
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
- // Version: 4.0.2019.08.13
- #pragma once
- #include <Mathematics/Logger.h>
- #include <algorithm>
- #include <initializer_list>
- #include <vector>
- namespace WwiseGTE
- {
- template <typename Real>
- class Polynomial1
- {
- public:
- // Construction and destruction. The first constructor creates a
- // polynomial of the specified degree but sets all coefficients to
- // zero (to ensure initialization). You are responsible for setting
- // the coefficients, presumably with the degree-term set to a nonzero
- // number. In the second constructor, the degree is the number of
- // initializers plus 1, but then adjusted so that coefficient[degree]
- // is not zero (unless all initializer values are zero).
- Polynomial1(unsigned int degree = 0)
- :
- mCoefficient(degree + 1, (Real)0)
- {
- }
- Polynomial1(std::initializer_list<Real> values)
- {
- // C++ 11 will call the default constructor for
- // Polynomial1<Real> p{}, so it is guaranteed that
- // values.size() > 0.
- mCoefficient.resize(values.size());
- std::copy(values.begin(), values.end(), mCoefficient.begin());
- EliminateLeadingZeros();
- }
- // Support for partial construction, where the default constructor is
- // used when the degree is not yet known. The coefficients are
- // uninitialized.
- void SetDegree(unsigned int degree)
- {
- mCoefficient.resize(degree + 1);
- }
- // Set all coefficients to the specified value.
- void SetCoefficients(Real value)
- {
- std::fill(mCoefficient.begin(), mCoefficient.end(), value);
- }
- // Member access.
- inline unsigned int GetDegree() const
- {
- // By design, mCoefficient.size() > 0.
- return static_cast<unsigned int>(mCoefficient.size() - 1);
- }
- inline Real const& operator[](unsigned int i) const
- {
- return mCoefficient[i];
- }
- inline Real& operator[](unsigned int i)
- {
- return mCoefficient[i];
- }
- // Comparisons.
- inline bool operator==(Polynomial1<Real> const& p) const
- {
- return mCoefficient == p.mCoefficient;
- }
- inline bool operator!=(Polynomial1<Real> const& p) const
- {
- return mCoefficient != p.mCoefficient;
- }
- inline bool operator< (Polynomial1<Real> const& p) const
- {
- return mCoefficient < p.mCoefficient;
- }
- inline bool operator<=(Polynomial1<Real> const& p) const
- {
- return mCoefficient <= p.mCoefficient;
- }
- inline bool operator> (Polynomial1<Real> const& p) const
- {
- return mCoefficient > p.mCoefficient;
- }
- inline bool operator>=(Polynomial1<Real> const& p) const
- {
- return mCoefficient >= p.mCoefficient;
- }
- // Evaluate the polynomial. If the polynomial is invalid, the
- // function returns zero.
- Real operator()(Real t) const
- {
- int i = static_cast<int>(mCoefficient.size());
- Real result = mCoefficient[--i];
- for (--i; i >= 0; --i)
- {
- result *= t;
- result += mCoefficient[i];
- }
- return result;
- }
- // Compute the derivative of the polynomial.
- Polynomial1 GetDerivative() const
- {
- unsigned int const degree = GetDegree();
- if (degree > 0)
- {
- Polynomial1 result(degree - 1);
- for (unsigned int i0 = 0, i1 = 1; i0 < degree; ++i0, ++i1)
- {
- result.mCoefficient[i0] = mCoefficient[i1] * (Real)i1;
- }
- return result;
- }
- else
- {
- Polynomial1 result(0);
- result[0] = (Real)0;
- return result;
- }
- }
- // Inversion (invpoly[i] = poly[degree-i] for 0 <= i <= degree).
- Polynomial1 GetInversion() const
- {
- unsigned int const degree = GetDegree();
- Polynomial1 result(degree);
- for (unsigned int i = 0; i <= degree; ++i)
- {
- result.mCoefficient[i] = mCoefficient[degree - i];
- }
- return result;
- }
- // Tranlation. If 'this' is p(t}, return p(t-t0).
- Polynomial1 GetTranslation(Real t0) const
- {
- Polynomial1<Real> factor{ -t0, (Real)1 }; // f(t) = t - t0
- unsigned int const degree = GetDegree();
- Polynomial1 result{ mCoefficient[degree] };
- for (unsigned int i = 1, j = degree - 1; i <= degree; ++i, --j)
- {
- result = mCoefficient[j] + factor * result;
- }
- return result;
- }
- // Eliminate any leading zeros in the polynomial, except in the case
- // the degree is 0 and the coefficient is 0. The elimination is
- // necessary when arithmetic operations cause a decrease in the degree
- // of the result. For example, (1 + x + x^2) + (1 + 2*x - x^2) =
- // (2 + 3*x). The inputs both have degree 2, so the result is created
- // with degree 2. After the addition we find that the degree is in
- // fact 1 and resize the array of coefficients. This function is
- // called internally by the arithmetic operators, but it is exposed in
- // the public interface in case you need it for your own purposes.
- void EliminateLeadingZeros()
- {
- size_t size = mCoefficient.size();
- if (size > 1)
- {
- Real const zero = (Real)0;
- int leading;
- for (leading = static_cast<int>(size) - 1; leading > 0; --leading)
- {
- if (mCoefficient[leading] != zero)
- {
- break;
- }
- }
- mCoefficient.resize(++leading);
- }
- }
- // If 'this' is P(t) and the divisor is D(t) with
- // degree(P) >= degree(D), then P(t) = Q(t)*D(t)+R(t) where Q(t) is
- // the quotient with degree(Q) = degree(P) - degree(D) and R(t) is the
- // remainder with degree(R) < degree(D). If this routine is called
- // with degree(P) < degree(D), then Q = 0 and R = P are returned.
- void Divide(Polynomial1 const& divisor, Polynomial1& quotient, Polynomial1& remainder) const
- {
- Real const zero = (Real)0;
- int divisorDegree = static_cast<int>(divisor.GetDegree());
- int quotientDegree = static_cast<int>(GetDegree()) - divisorDegree;
- if (quotientDegree >= 0)
- {
- quotient.SetDegree(quotientDegree);
- // Temporary storage for the remainder.
- Polynomial1 tmp = *this;
- // Do the division using the Euclidean algorithm.
- Real inv = ((Real)1) / divisor[divisorDegree];
- for (int i = quotientDegree; i >= 0; --i)
- {
- int j = divisorDegree + i;
- quotient[i] = inv * tmp[j];
- for (j--; j >= i; j--)
- {
- tmp[j] -= quotient[i] * divisor[j - i];
- }
- }
- // Calculate the correct degree for the remainder.
- if (divisorDegree >= 1)
- {
- int remainderDegree = divisorDegree - 1;
- while (remainderDegree > 0 && tmp[remainderDegree] == zero)
- {
- --remainderDegree;
- }
- remainder.SetDegree(remainderDegree);
- for (int i = 0; i <= remainderDegree; ++i)
- {
- remainder[i] = tmp[i];
- }
- }
- else
- {
- remainder.SetDegree(0);
- remainder[0] = zero;
- }
- }
- else
- {
- quotient.SetDegree(0);
- quotient[0] = zero;
- remainder = *this;
- }
- }
- // Scale the polynomial so the highest-degree term has coefficient 1.
- void MakeMonic()
- {
- EliminateLeadingZeros();
- Real const one(1);
- if (mCoefficient.back() != one)
- {
- unsigned int degree = GetDegree();
- Real invLeading = one / mCoefficient.back();
- mCoefficient.back() = one;
- for (unsigned int i = 0; i < degree; ++i)
- {
- mCoefficient[i] *= invLeading;
- }
- }
- }
- protected:
- // The class is designed so that mCoefficient.size() >= 1.
- std::vector<Real> mCoefficient;
- };
- // Compute the greatest common divisor of two polynomials. The returned
- // polynomial has leading coefficient 1 (except when zero-valued
- // polynomials are passed to the function.
- template <typename Real>
- Polynomial1<Real> GreatestCommonDivisor(Polynomial1<Real> const& p0, Polynomial1<Real> const& p1)
- {
- // The numerator should be the polynomial of larger degree.
- Polynomial1<Real> a, b;
- if (p0.GetDegree() >= p1.GetDegree())
- {
- a = p0;
- b = p1;
- }
- else
- {
- a = p1;
- b = p0;
- }
- Polynomial1<Real> const zero{ (Real)0 };
- if (a == zero || b == zero)
- {
- return (a != zero ? a : zero);
- }
- // Make the polynomials monic to keep the coefficients reasonable size
- // when computing with floating-point Real.
- a.MakeMonic();
- b.MakeMonic();
- Polynomial1<Real> q, r;
- for (;;)
- {
- a.Divide(b, q, r);
- if (r != zero)
- {
- // a = q * b + r, so gcd(a,b) = gcd(b, r)
- a = b;
- b = r;
- b.MakeMonic();
- }
- else
- {
- b.MakeMonic();
- break;
- }
- }
- return b;
- }
- // Factor f = factor[0]*factor[1]^2*factor[2]^3*...*factor[n-1]^n
- // according to the square-free factorization algorithm
- // https://en.wikipedia.org/wiki/Square-free_polynomial
- template <typename Real>
- void SquareFreeFactorization(Polynomial1<Real> const& f, std::vector<Polynomial1<Real>>& factors)
- {
- // In the call to Divide(...), we know that the divisor exactly
- // divides the numerator, so r = 0 after all such calls.
- Polynomial1<Real> fder = f.GetDerivative();
- Polynomial1<Real> a, b, c, d, q, r;
- a = GreatestCommonDivisor(f, fder);
- f.Divide(a, b, r); // b = f / a
- fder.Divide(a, c, r); // c = fder / a
- d = c - b.GetDerivative();
- do
- {
- a = GreatestCommonDivisor(b, d);
- factors.emplace_back(a);
- b.Divide(a, q, r); // q = b / a
- b = std::move(q);
- d.Divide(a, c, r); // c = d / a
- d = c - b.GetDerivative();
- } while (b.GetDegree() > 0);
- }
- // Unary operations.
- template <typename Real>
- Polynomial1<Real> operator+(Polynomial1<Real> const& p)
- {
- return p;
- }
- template <typename Real>
- Polynomial1<Real> operator-(Polynomial1<Real> const& p)
- {
- unsigned int const degree = p.GetDegree();
- Polynomial1<Real> result(degree);
- for (unsigned int i = 0; i <= degree; ++i)
- {
- result[i] = -p[i];
- }
- return result;
- }
- // Linear-algebraic operations.
- template <typename Real>
- Polynomial1<Real> operator+(Polynomial1<Real> const& p0, Polynomial1<Real> const& p1)
- {
- unsigned int const p0Degree = p0.GetDegree(), p1Degree = p1.GetDegree();
- unsigned int i;
- if (p0Degree >= p1Degree)
- {
- Polynomial1<Real> result(p0Degree);
- for (i = 0; i <= p1Degree; ++i)
- {
- result[i] = p0[i] + p1[i];
- }
- for (/**/; i <= p0Degree; ++i)
- {
- result[i] = p0[i];
- }
- result.EliminateLeadingZeros();
- return result;
- }
- else
- {
- Polynomial1<Real> result(p1Degree);
- for (i = 0; i <= p0Degree; ++i)
- {
- result[i] = p0[i] + p1[i];
- }
- for (/**/; i <= p1Degree; ++i)
- {
- result[i] = p1[i];
- }
- result.EliminateLeadingZeros();
- return result;
- }
- }
- template <typename Real>
- Polynomial1<Real> operator-(Polynomial1<Real> const& p0, Polynomial1<Real> const& p1)
- {
- unsigned int const p0Degree = p0.GetDegree(), p1Degree = p1.GetDegree();
- unsigned int i;
- if (p0Degree >= p1Degree)
- {
- Polynomial1<Real> result(p0Degree);
- for (i = 0; i <= p1Degree; ++i)
- {
- result[i] = p0[i] - p1[i];
- }
- for (/**/; i <= p0Degree; ++i)
- {
- result[i] = p0[i];
- }
- result.EliminateLeadingZeros();
- return result;
- }
- else
- {
- Polynomial1<Real> result(p1Degree);
- for (i = 0; i <= p0Degree; ++i)
- {
- result[i] = p0[i] - p1[i];
- }
- for (/**/; i <= p1Degree; ++i)
- {
- result[i] = -p1[i];
- }
- result.EliminateLeadingZeros();
- return result;
- }
- }
- template <typename Real>
- Polynomial1<Real> operator*(Polynomial1<Real> const& p0, Polynomial1<Real> const& p1)
- {
- unsigned int const p0Degree = p0.GetDegree(), p1Degree = p1.GetDegree();
- Polynomial1<Real> result(p0Degree + p1Degree);
- result.SetCoefficients((Real)0);
- for (unsigned int i0 = 0; i0 <= p0Degree; ++i0)
- {
- for (unsigned int i1 = 0; i1 <= p1Degree; ++i1)
- {
- result[i0 + i1] += p0[i0] * p1[i1];
- }
- }
- return result;
- }
- template <typename Real>
- Polynomial1<Real> operator+(Polynomial1<Real> const& p, Real scalar)
- {
- unsigned int const degree = p.GetDegree();
- Polynomial1<Real> result(degree);
- result[0] = p[0] + scalar;
- for (unsigned int i = 1; i <= degree; ++i)
- {
- result[i] = p[i];
- }
- return result;
- }
- template <typename Real>
- Polynomial1<Real> operator+(Real scalar, Polynomial1<Real> const& p)
- {
- unsigned int const degree = p.GetDegree();
- Polynomial1<Real> result(degree);
- result[0] = p[0] + scalar;
- for (unsigned int i = 1; i <= degree; ++i)
- {
- result[i] = p[i];
- }
- return result;
- }
- template <typename Real>
- Polynomial1<Real> operator-(Polynomial1<Real> const& p, Real scalar)
- {
- unsigned int const degree = p.GetDegree();
- Polynomial1<Real> result(degree);
- result[0] = p[0] - scalar;
- for (unsigned int i = 1; i <= degree; ++i)
- {
- result[i] = p[i];
- }
- return result;
- }
- template <typename Real>
- Polynomial1<Real> operator-(Real scalar, Polynomial1<Real> const& p)
- {
- unsigned int const degree = p.GetDegree();
- Polynomial1<Real> result(degree);
- result[0] = scalar - p[0];
- for (unsigned int i = 1; i <= degree; ++i)
- {
- result[i] = -p[i];
- }
- return result;
- }
- template <typename Real>
- Polynomial1<Real> operator*(Polynomial1<Real> const& p, Real scalar)
- {
- unsigned int const degree = p.GetDegree();
- Polynomial1<Real> result(degree);
- for (unsigned int i = 0; i <= degree; ++i)
- {
- result[i] = scalar * p[i];
- }
- return result;
- }
- template <typename Real>
- Polynomial1<Real> operator*(Real scalar, Polynomial1<Real> const& p)
- {
- unsigned int const degree = p.GetDegree();
- Polynomial1<Real> result(degree);
- for (unsigned int i = 0; i <= degree; ++i)
- {
- result[i] = scalar * p[i];
- }
- return result;
- }
- template <typename Real>
- Polynomial1<Real> operator/(Polynomial1<Real> const& p, Real scalar)
- {
- LogAssert(scalar != (Real)0, "Division by zero.");
- unsigned int const degree = p.GetDegree();
- Real invScalar = (Real)1 / scalar;
- Polynomial1<Real> result(degree);
- for (unsigned int i = 0; i <= degree; ++i)
- {
- result[i] = invScalar * p[i];
- }
- return result;
- }
- template <typename Real>
- Polynomial1<Real>& operator+=(Polynomial1<Real>& p0, Polynomial1<Real> const& p1)
- {
- p0 = p0 + p1;
- return p0;
- }
- template <typename Real>
- Polynomial1<Real>& operator-=(Polynomial1<Real>& p0, Polynomial1<Real> const& p1)
- {
- p0 = p0 - p1;
- return p0;
- }
- template <typename Real>
- Polynomial1<Real>& operator*=(Polynomial1<Real>& p0, Polynomial1<Real> const& p1)
- {
- p0 = p0 * p1;
- return p0;
- }
- template <typename Real>
- Polynomial1<Real>& operator+=(Polynomial1<Real>& p, Real scalar)
- {
- p[0] += scalar;
- return p;
- }
- template <typename Real>
- Polynomial1<Real>& operator-=(Polynomial1<Real>& p, Real scalar)
- {
- p[0] -= scalar;
- return p;
- }
- template <typename Real>
- Polynomial1<Real>& operator*=(Polynomial1<Real>& p, Real scalar)
- {
- p = p * scalar;
- return p;
- }
- template <typename Real>
- Polynomial1<Real> & operator/=(Polynomial1<Real>& p, Real scalar)
- {
- p = p / scalar;
- return p;
- }
- }
|