Polynomial1.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/Logger.h>
  9. #include <algorithm>
  10. #include <initializer_list>
  11. #include <vector>
  12. namespace WwiseGTE
  13. {
  14. template <typename Real>
  15. class Polynomial1
  16. {
  17. public:
  18. // Construction and destruction. The first constructor creates a
  19. // polynomial of the specified degree but sets all coefficients to
  20. // zero (to ensure initialization). You are responsible for setting
  21. // the coefficients, presumably with the degree-term set to a nonzero
  22. // number. In the second constructor, the degree is the number of
  23. // initializers plus 1, but then adjusted so that coefficient[degree]
  24. // is not zero (unless all initializer values are zero).
  25. Polynomial1(unsigned int degree = 0)
  26. :
  27. mCoefficient(degree + 1, (Real)0)
  28. {
  29. }
  30. Polynomial1(std::initializer_list<Real> values)
  31. {
  32. // C++ 11 will call the default constructor for
  33. // Polynomial1<Real> p{}, so it is guaranteed that
  34. // values.size() > 0.
  35. mCoefficient.resize(values.size());
  36. std::copy(values.begin(), values.end(), mCoefficient.begin());
  37. EliminateLeadingZeros();
  38. }
  39. // Support for partial construction, where the default constructor is
  40. // used when the degree is not yet known. The coefficients are
  41. // uninitialized.
  42. void SetDegree(unsigned int degree)
  43. {
  44. mCoefficient.resize(degree + 1);
  45. }
  46. // Set all coefficients to the specified value.
  47. void SetCoefficients(Real value)
  48. {
  49. std::fill(mCoefficient.begin(), mCoefficient.end(), value);
  50. }
  51. // Member access.
  52. inline unsigned int GetDegree() const
  53. {
  54. // By design, mCoefficient.size() > 0.
  55. return static_cast<unsigned int>(mCoefficient.size() - 1);
  56. }
  57. inline Real const& operator[](unsigned int i) const
  58. {
  59. return mCoefficient[i];
  60. }
  61. inline Real& operator[](unsigned int i)
  62. {
  63. return mCoefficient[i];
  64. }
  65. // Comparisons.
  66. inline bool operator==(Polynomial1<Real> const& p) const
  67. {
  68. return mCoefficient == p.mCoefficient;
  69. }
  70. inline bool operator!=(Polynomial1<Real> const& p) const
  71. {
  72. return mCoefficient != p.mCoefficient;
  73. }
  74. inline bool operator< (Polynomial1<Real> const& p) const
  75. {
  76. return mCoefficient < p.mCoefficient;
  77. }
  78. inline bool operator<=(Polynomial1<Real> const& p) const
  79. {
  80. return mCoefficient <= p.mCoefficient;
  81. }
  82. inline bool operator> (Polynomial1<Real> const& p) const
  83. {
  84. return mCoefficient > p.mCoefficient;
  85. }
  86. inline bool operator>=(Polynomial1<Real> const& p) const
  87. {
  88. return mCoefficient >= p.mCoefficient;
  89. }
  90. // Evaluate the polynomial. If the polynomial is invalid, the
  91. // function returns zero.
  92. Real operator()(Real t) const
  93. {
  94. int i = static_cast<int>(mCoefficient.size());
  95. Real result = mCoefficient[--i];
  96. for (--i; i >= 0; --i)
  97. {
  98. result *= t;
  99. result += mCoefficient[i];
  100. }
  101. return result;
  102. }
  103. // Compute the derivative of the polynomial.
  104. Polynomial1 GetDerivative() const
  105. {
  106. unsigned int const degree = GetDegree();
  107. if (degree > 0)
  108. {
  109. Polynomial1 result(degree - 1);
  110. for (unsigned int i0 = 0, i1 = 1; i0 < degree; ++i0, ++i1)
  111. {
  112. result.mCoefficient[i0] = mCoefficient[i1] * (Real)i1;
  113. }
  114. return result;
  115. }
  116. else
  117. {
  118. Polynomial1 result(0);
  119. result[0] = (Real)0;
  120. return result;
  121. }
  122. }
  123. // Inversion (invpoly[i] = poly[degree-i] for 0 <= i <= degree).
  124. Polynomial1 GetInversion() const
  125. {
  126. unsigned int const degree = GetDegree();
  127. Polynomial1 result(degree);
  128. for (unsigned int i = 0; i <= degree; ++i)
  129. {
  130. result.mCoefficient[i] = mCoefficient[degree - i];
  131. }
  132. return result;
  133. }
  134. // Tranlation. If 'this' is p(t}, return p(t-t0).
  135. Polynomial1 GetTranslation(Real t0) const
  136. {
  137. Polynomial1<Real> factor{ -t0, (Real)1 }; // f(t) = t - t0
  138. unsigned int const degree = GetDegree();
  139. Polynomial1 result{ mCoefficient[degree] };
  140. for (unsigned int i = 1, j = degree - 1; i <= degree; ++i, --j)
  141. {
  142. result = mCoefficient[j] + factor * result;
  143. }
  144. return result;
  145. }
  146. // Eliminate any leading zeros in the polynomial, except in the case
  147. // the degree is 0 and the coefficient is 0. The elimination is
  148. // necessary when arithmetic operations cause a decrease in the degree
  149. // of the result. For example, (1 + x + x^2) + (1 + 2*x - x^2) =
  150. // (2 + 3*x). The inputs both have degree 2, so the result is created
  151. // with degree 2. After the addition we find that the degree is in
  152. // fact 1 and resize the array of coefficients. This function is
  153. // called internally by the arithmetic operators, but it is exposed in
  154. // the public interface in case you need it for your own purposes.
  155. void EliminateLeadingZeros()
  156. {
  157. size_t size = mCoefficient.size();
  158. if (size > 1)
  159. {
  160. Real const zero = (Real)0;
  161. int leading;
  162. for (leading = static_cast<int>(size) - 1; leading > 0; --leading)
  163. {
  164. if (mCoefficient[leading] != zero)
  165. {
  166. break;
  167. }
  168. }
  169. mCoefficient.resize(++leading);
  170. }
  171. }
  172. // If 'this' is P(t) and the divisor is D(t) with
  173. // degree(P) >= degree(D), then P(t) = Q(t)*D(t)+R(t) where Q(t) is
  174. // the quotient with degree(Q) = degree(P) - degree(D) and R(t) is the
  175. // remainder with degree(R) < degree(D). If this routine is called
  176. // with degree(P) < degree(D), then Q = 0 and R = P are returned.
  177. void Divide(Polynomial1 const& divisor, Polynomial1& quotient, Polynomial1& remainder) const
  178. {
  179. Real const zero = (Real)0;
  180. int divisorDegree = static_cast<int>(divisor.GetDegree());
  181. int quotientDegree = static_cast<int>(GetDegree()) - divisorDegree;
  182. if (quotientDegree >= 0)
  183. {
  184. quotient.SetDegree(quotientDegree);
  185. // Temporary storage for the remainder.
  186. Polynomial1 tmp = *this;
  187. // Do the division using the Euclidean algorithm.
  188. Real inv = ((Real)1) / divisor[divisorDegree];
  189. for (int i = quotientDegree; i >= 0; --i)
  190. {
  191. int j = divisorDegree + i;
  192. quotient[i] = inv * tmp[j];
  193. for (j--; j >= i; j--)
  194. {
  195. tmp[j] -= quotient[i] * divisor[j - i];
  196. }
  197. }
  198. // Calculate the correct degree for the remainder.
  199. if (divisorDegree >= 1)
  200. {
  201. int remainderDegree = divisorDegree - 1;
  202. while (remainderDegree > 0 && tmp[remainderDegree] == zero)
  203. {
  204. --remainderDegree;
  205. }
  206. remainder.SetDegree(remainderDegree);
  207. for (int i = 0; i <= remainderDegree; ++i)
  208. {
  209. remainder[i] = tmp[i];
  210. }
  211. }
  212. else
  213. {
  214. remainder.SetDegree(0);
  215. remainder[0] = zero;
  216. }
  217. }
  218. else
  219. {
  220. quotient.SetDegree(0);
  221. quotient[0] = zero;
  222. remainder = *this;
  223. }
  224. }
  225. // Scale the polynomial so the highest-degree term has coefficient 1.
  226. void MakeMonic()
  227. {
  228. EliminateLeadingZeros();
  229. Real const one(1);
  230. if (mCoefficient.back() != one)
  231. {
  232. unsigned int degree = GetDegree();
  233. Real invLeading = one / mCoefficient.back();
  234. mCoefficient.back() = one;
  235. for (unsigned int i = 0; i < degree; ++i)
  236. {
  237. mCoefficient[i] *= invLeading;
  238. }
  239. }
  240. }
  241. protected:
  242. // The class is designed so that mCoefficient.size() >= 1.
  243. std::vector<Real> mCoefficient;
  244. };
  245. // Compute the greatest common divisor of two polynomials. The returned
  246. // polynomial has leading coefficient 1 (except when zero-valued
  247. // polynomials are passed to the function.
  248. template <typename Real>
  249. Polynomial1<Real> GreatestCommonDivisor(Polynomial1<Real> const& p0, Polynomial1<Real> const& p1)
  250. {
  251. // The numerator should be the polynomial of larger degree.
  252. Polynomial1<Real> a, b;
  253. if (p0.GetDegree() >= p1.GetDegree())
  254. {
  255. a = p0;
  256. b = p1;
  257. }
  258. else
  259. {
  260. a = p1;
  261. b = p0;
  262. }
  263. Polynomial1<Real> const zero{ (Real)0 };
  264. if (a == zero || b == zero)
  265. {
  266. return (a != zero ? a : zero);
  267. }
  268. // Make the polynomials monic to keep the coefficients reasonable size
  269. // when computing with floating-point Real.
  270. a.MakeMonic();
  271. b.MakeMonic();
  272. Polynomial1<Real> q, r;
  273. for (;;)
  274. {
  275. a.Divide(b, q, r);
  276. if (r != zero)
  277. {
  278. // a = q * b + r, so gcd(a,b) = gcd(b, r)
  279. a = b;
  280. b = r;
  281. b.MakeMonic();
  282. }
  283. else
  284. {
  285. b.MakeMonic();
  286. break;
  287. }
  288. }
  289. return b;
  290. }
  291. // Factor f = factor[0]*factor[1]^2*factor[2]^3*...*factor[n-1]^n
  292. // according to the square-free factorization algorithm
  293. // https://en.wikipedia.org/wiki/Square-free_polynomial
  294. template <typename Real>
  295. void SquareFreeFactorization(Polynomial1<Real> const& f, std::vector<Polynomial1<Real>>& factors)
  296. {
  297. // In the call to Divide(...), we know that the divisor exactly
  298. // divides the numerator, so r = 0 after all such calls.
  299. Polynomial1<Real> fder = f.GetDerivative();
  300. Polynomial1<Real> a, b, c, d, q, r;
  301. a = GreatestCommonDivisor(f, fder);
  302. f.Divide(a, b, r); // b = f / a
  303. fder.Divide(a, c, r); // c = fder / a
  304. d = c - b.GetDerivative();
  305. do
  306. {
  307. a = GreatestCommonDivisor(b, d);
  308. factors.emplace_back(a);
  309. b.Divide(a, q, r); // q = b / a
  310. b = std::move(q);
  311. d.Divide(a, c, r); // c = d / a
  312. d = c - b.GetDerivative();
  313. } while (b.GetDegree() > 0);
  314. }
  315. // Unary operations.
  316. template <typename Real>
  317. Polynomial1<Real> operator+(Polynomial1<Real> const& p)
  318. {
  319. return p;
  320. }
  321. template <typename Real>
  322. Polynomial1<Real> operator-(Polynomial1<Real> const& p)
  323. {
  324. unsigned int const degree = p.GetDegree();
  325. Polynomial1<Real> result(degree);
  326. for (unsigned int i = 0; i <= degree; ++i)
  327. {
  328. result[i] = -p[i];
  329. }
  330. return result;
  331. }
  332. // Linear-algebraic operations.
  333. template <typename Real>
  334. Polynomial1<Real> operator+(Polynomial1<Real> const& p0, Polynomial1<Real> const& p1)
  335. {
  336. unsigned int const p0Degree = p0.GetDegree(), p1Degree = p1.GetDegree();
  337. unsigned int i;
  338. if (p0Degree >= p1Degree)
  339. {
  340. Polynomial1<Real> result(p0Degree);
  341. for (i = 0; i <= p1Degree; ++i)
  342. {
  343. result[i] = p0[i] + p1[i];
  344. }
  345. for (/**/; i <= p0Degree; ++i)
  346. {
  347. result[i] = p0[i];
  348. }
  349. result.EliminateLeadingZeros();
  350. return result;
  351. }
  352. else
  353. {
  354. Polynomial1<Real> result(p1Degree);
  355. for (i = 0; i <= p0Degree; ++i)
  356. {
  357. result[i] = p0[i] + p1[i];
  358. }
  359. for (/**/; i <= p1Degree; ++i)
  360. {
  361. result[i] = p1[i];
  362. }
  363. result.EliminateLeadingZeros();
  364. return result;
  365. }
  366. }
  367. template <typename Real>
  368. Polynomial1<Real> operator-(Polynomial1<Real> const& p0, Polynomial1<Real> const& p1)
  369. {
  370. unsigned int const p0Degree = p0.GetDegree(), p1Degree = p1.GetDegree();
  371. unsigned int i;
  372. if (p0Degree >= p1Degree)
  373. {
  374. Polynomial1<Real> result(p0Degree);
  375. for (i = 0; i <= p1Degree; ++i)
  376. {
  377. result[i] = p0[i] - p1[i];
  378. }
  379. for (/**/; i <= p0Degree; ++i)
  380. {
  381. result[i] = p0[i];
  382. }
  383. result.EliminateLeadingZeros();
  384. return result;
  385. }
  386. else
  387. {
  388. Polynomial1<Real> result(p1Degree);
  389. for (i = 0; i <= p0Degree; ++i)
  390. {
  391. result[i] = p0[i] - p1[i];
  392. }
  393. for (/**/; i <= p1Degree; ++i)
  394. {
  395. result[i] = -p1[i];
  396. }
  397. result.EliminateLeadingZeros();
  398. return result;
  399. }
  400. }
  401. template <typename Real>
  402. Polynomial1<Real> operator*(Polynomial1<Real> const& p0, Polynomial1<Real> const& p1)
  403. {
  404. unsigned int const p0Degree = p0.GetDegree(), p1Degree = p1.GetDegree();
  405. Polynomial1<Real> result(p0Degree + p1Degree);
  406. result.SetCoefficients((Real)0);
  407. for (unsigned int i0 = 0; i0 <= p0Degree; ++i0)
  408. {
  409. for (unsigned int i1 = 0; i1 <= p1Degree; ++i1)
  410. {
  411. result[i0 + i1] += p0[i0] * p1[i1];
  412. }
  413. }
  414. return result;
  415. }
  416. template <typename Real>
  417. Polynomial1<Real> operator+(Polynomial1<Real> const& p, Real scalar)
  418. {
  419. unsigned int const degree = p.GetDegree();
  420. Polynomial1<Real> result(degree);
  421. result[0] = p[0] + scalar;
  422. for (unsigned int i = 1; i <= degree; ++i)
  423. {
  424. result[i] = p[i];
  425. }
  426. return result;
  427. }
  428. template <typename Real>
  429. Polynomial1<Real> operator+(Real scalar, Polynomial1<Real> const& p)
  430. {
  431. unsigned int const degree = p.GetDegree();
  432. Polynomial1<Real> result(degree);
  433. result[0] = p[0] + scalar;
  434. for (unsigned int i = 1; i <= degree; ++i)
  435. {
  436. result[i] = p[i];
  437. }
  438. return result;
  439. }
  440. template <typename Real>
  441. Polynomial1<Real> operator-(Polynomial1<Real> const& p, Real scalar)
  442. {
  443. unsigned int const degree = p.GetDegree();
  444. Polynomial1<Real> result(degree);
  445. result[0] = p[0] - scalar;
  446. for (unsigned int i = 1; i <= degree; ++i)
  447. {
  448. result[i] = p[i];
  449. }
  450. return result;
  451. }
  452. template <typename Real>
  453. Polynomial1<Real> operator-(Real scalar, Polynomial1<Real> const& p)
  454. {
  455. unsigned int const degree = p.GetDegree();
  456. Polynomial1<Real> result(degree);
  457. result[0] = scalar - p[0];
  458. for (unsigned int i = 1; i <= degree; ++i)
  459. {
  460. result[i] = -p[i];
  461. }
  462. return result;
  463. }
  464. template <typename Real>
  465. Polynomial1<Real> operator*(Polynomial1<Real> const& p, Real scalar)
  466. {
  467. unsigned int const degree = p.GetDegree();
  468. Polynomial1<Real> result(degree);
  469. for (unsigned int i = 0; i <= degree; ++i)
  470. {
  471. result[i] = scalar * p[i];
  472. }
  473. return result;
  474. }
  475. template <typename Real>
  476. Polynomial1<Real> operator*(Real scalar, Polynomial1<Real> const& p)
  477. {
  478. unsigned int const degree = p.GetDegree();
  479. Polynomial1<Real> result(degree);
  480. for (unsigned int i = 0; i <= degree; ++i)
  481. {
  482. result[i] = scalar * p[i];
  483. }
  484. return result;
  485. }
  486. template <typename Real>
  487. Polynomial1<Real> operator/(Polynomial1<Real> const& p, Real scalar)
  488. {
  489. LogAssert(scalar != (Real)0, "Division by zero.");
  490. unsigned int const degree = p.GetDegree();
  491. Real invScalar = (Real)1 / scalar;
  492. Polynomial1<Real> result(degree);
  493. for (unsigned int i = 0; i <= degree; ++i)
  494. {
  495. result[i] = invScalar * p[i];
  496. }
  497. return result;
  498. }
  499. template <typename Real>
  500. Polynomial1<Real>& operator+=(Polynomial1<Real>& p0, Polynomial1<Real> const& p1)
  501. {
  502. p0 = p0 + p1;
  503. return p0;
  504. }
  505. template <typename Real>
  506. Polynomial1<Real>& operator-=(Polynomial1<Real>& p0, Polynomial1<Real> const& p1)
  507. {
  508. p0 = p0 - p1;
  509. return p0;
  510. }
  511. template <typename Real>
  512. Polynomial1<Real>& operator*=(Polynomial1<Real>& p0, Polynomial1<Real> const& p1)
  513. {
  514. p0 = p0 * p1;
  515. return p0;
  516. }
  517. template <typename Real>
  518. Polynomial1<Real>& operator+=(Polynomial1<Real>& p, Real scalar)
  519. {
  520. p[0] += scalar;
  521. return p;
  522. }
  523. template <typename Real>
  524. Polynomial1<Real>& operator-=(Polynomial1<Real>& p, Real scalar)
  525. {
  526. p[0] -= scalar;
  527. return p;
  528. }
  529. template <typename Real>
  530. Polynomial1<Real>& operator*=(Polynomial1<Real>& p, Real scalar)
  531. {
  532. p = p * scalar;
  533. return p;
  534. }
  535. template <typename Real>
  536. Polynomial1<Real> & operator/=(Polynomial1<Real>& p, Real scalar)
  537. {
  538. p = p / scalar;
  539. return p;
  540. }
  541. }